Maison  >  Article  >  interface Web  >  Promesses en JavaScript : compréhension, gestion et maîtrise du code asynchrone

Promesses en JavaScript : compréhension, gestion et maîtrise du code asynchrone

WBOY
WBOYoriginal
2024-09-03 14:18:32701parcourir

Promises in JavaScript: Understanding, Handling, and Mastering Async Code

Introduction

J'ai travaillé en tant que développeur Java et je me souviens pour la première fois du moment où j'ai été en contact avec des promesses en JavaScript. Même si le concept semblait simple, je n’arrivais toujours pas à comprendre pleinement comment fonctionnait Promises. Cela a changé lorsque j'ai commencé à les utiliser dans des projets et que j'ai compris les cas qu'ils résolvaient. Puis vint le moment AHA et tout devint plus clair. Au fil du temps, les promesses sont devenues une arme précieuse sur ma ceinture à outils. C'est étrangement satisfaisant de pouvoir les utiliser au travail et résoudre la gestion asynchrone entre les fonctions.

Vous rencontrez probablement des promesses pour la première fois lors de la récupération de données à partir d'une API, ce qui est également l'exemple le plus courant. Récemment, j'ai été interviewé et devinez quelle était la première question « Pouvez-vous me dire la différence entre Promise et Async Await ? Je m’en réjouis car je considère que c’est un bon point de départ pour mieux savoir comment le demandeur comprend le fonctionnement des mécanismes. Cependant, il utilise principalement d’autres bibliothèques et frameworks. Cela m'a permis d'écrire les différences et de décrire les bonnes pratiques pour gérer les erreurs de fonction asynchrone.

Quelle est la promesse

Commençons par la question initiale : « Quelle est la promesse ? » La promesse est un espace réservé pour la valeur que nous ne connaissons pas encore mais nous l'obtiendrons grâce à un calcul/une fonction asynchrone. Si la promesse se déroule bien, nous obtiendrons le résultat. Si la promesse ne se passe pas bien, alors la promesse renverra une erreur.

Un exemple basique de promesse

Définir une promesse

Vous définissez Promise en appelant son constructeur et en passant deux fonctions de rappel : resolve et reject.

const newPromise = new Promise((resolve, reject) => {
    resolve('Hello');
    // reject('Error');
});

Nous appelons la fonction de résolution lorsque nous voulons résoudre avec succès la promesse. rejeter sert à rejeter la promesse dans le cas où une erreur se produit lors de l'évaluation de notre logique.

Récupération du résultat de la promesse

Nous utilisons ensuite la fonction intégrée pour obtenir le résultat de la promesse. Il a deux rappels passés, un résultat et une erreur. Le résultat est appelé lorsque la promesse est résolue avec succès par la fonction solve. Si la promesse n'est pas résolue, la deuxième erreur de fonction est appelée. Cette fonction est déclenchée soit par un rejet, soit par une autre erreur générée.

newPromise.then(result => {
    console.log(result); // Hello
}, error => {
    console.log("There shouldn't be an error");
});

Dans notre exemple, nous obtiendrons le résultat Bonjour car nous avons réussi à résoudre la Promesse.

Gestion des erreurs des promesses

Lorsque la promesse est rejetée, son deuxième rappel d'erreur est toujours invoqué.

const newPromise1 = new Promise((resolve, reject) => {
  reject('An error occurred in Promise1');
});

newPromise1.then(
  (result) => {
    console.log(result); // It is not invoked
  },
  (error) => {
    console.log(error); // 'An error occurred in Promise1'
  }
);

Une approche plus recommandée pour sa clarté consiste à utiliser la méthode catch intégrée.

const newPromise2 = new Promise((resolve, reject) => {
  reject('An error occurred in Promise2');
});

newPromise2
  .then((result) => {
    console.log(result); // It is not invoked
  })
  .catch((error) => {
    console.log(error); // 'An error occurred in Promise2'
  });

La méthode catch est chaînée et a fourni son propre rappel d'erreur. Il est invoqué lorsque la promesse est rejetée.

Les deux versions fonctionnent bien mais le chaînage est IMO plus lisible et il est pratique lors de l'utilisation d'autres méthodes intégrées que nous aborderons plus en détail.

Enchaîner les promesses

Le résultat d'une promesse pourrait probablement être une autre promesse. Dans ce cas, nous pouvons enchaîner un nombre arbitraire de fonctions then.

getJSON('categories.json')
    .then(categories => {
        console.log('Fetched categories:', categories);

        return getJSON(categories[0].itemsUrl);
    })
    .then(items => {
        console.log('Fetched items:', items);

        return getJSON(items[0].detailsUrl);
    })
    .then(details => {
        console.log('Fetched details:', details);
    })
    .catch(error => {
        console.error('An error has occurred:', error.message);
    });

Dans notre exemple, il sert à affiner les résultats de recherche pour obtenir des données détaillées. Chaque fonction then peut également avoir son rappel d'erreur. Si nous nous soucions uniquement de détecter toute erreur dans la chaîne d’appels, nous pouvons alors exploiter la fonction catch. Il sera évalué si l'une des promesses renvoie une erreur.

Promets tout

Parfois, nous voulons attendre les résultats de promesses plus indépendantes, puis agir en fonction des résultats. Nous pouvons utiliser la fonction intégrée Promise.all si nous ne nous soucions pas de l'ordre dans lequel les promesses ont été résolues.

Promise.all([
    getJSON('categories.json'),
    getJSON('technology_items.json'),
    getJSON('science_items.json')
])
    .then(results => {
        const categories = results[0];
        const techItems = results[1];
        const scienceItems = results[2];

        console.log('Fetched categories:', categories);
        console.log('Fetched technology items:', techItems);
        console.log('Fetched science items:', scienceItems);

        // Fetch details of the first item in each category
        return Promise.all([
            getJSON(techItems[0].detailsUrl),
            getJSON(scienceItems[0].detailsUrl)
        ]);
    })
    .then(detailsResults => {
        const laptopDetails = detailsResults[0];
        const physicsDetails = detailsResults[1];

        console.log('Fetched laptop details:', laptopDetails);
        console.log('Fetched physics details:', physicsDetails);
    })
    .catch(error => {
        console.error('An error has occurred:', error.message);
    });

Promise.all prend un tableau de promesses et renvoie un tableau de résultats. Si l'une des promesses est rejetée, alors Promise.all est également rejetée.

Promesses de course

Une autre fonctionnalité intégrée est Promise.race. Il est utilisé lorsque vous disposez de plusieurs fonctions asynchrones - Promesses - et que vous souhaitez les piloter.

Promise.race([
    getJSON('technology_items.json'),
    getJSON('science_items.json')
])
    .then(result => {
        console.log('First resolved data:', result);
    })
    .catch(error => {
        console.error('An error has occurred:', error.message);
    });

L'exécution des promesses peut prendre des temps différents et Promise.race évalue la première promesse résolue ou rejetée du tableau. Il est utilisé lorsque nous ne nous soucions pas de la commande mais que nous voulons le résultat de l'appel asynchrone le plus rapide.

Qu'est-ce que l'attente asynchrone

Comme vous pouvez le constater, écrire des promesses nécessite beaucoup de code passe-partout. Heureusement, nous disposons de la fonctionnalité native Async Await, qui rend l'utilisation des promesses encore plus facile. Nous marquons une fonction par le mot async et par là, nous disons que quelque part dans le code nous appellerons la fonction asynchrone et que nous ne devrions pas l'attendre. Ensuite, la fonction asynchrone est appelée avec le mot wait.

Basic example of Async Await

const fetchData = async () => {
    try {
        // Fetch the categories
        const categories = await getJSON('categories.json');
        console.log('Fetched categories:', categories);

        // Fetch items from the first category (Technology)
        const techItems = await getJSON(categories[0].itemsUrl);
        console.log('Fetched technology items:', techItems);

        // Fetch details of the first item in Technology (Laptops)
        const laptopDetails = await getJSON(techItems[0].detailsUrl);
        console.log('Fetched laptop details:', laptopDetails);
    } catch (error) {
        console.error('An error has occurred:', error.message);
    }
};

fetchData();

Our fetchData is marked as async and it allows us to use await to handle asynchronous calls inside the function. We call more Promises and they will evaluated one after the other.

We use try...catch block if we want handle the errors. Rejected error is then caught in the catch block and we can act on it like logging the error.

What’s different

They are both features of JavaScript handling with asynchronous code. The main difference is in the syntax when Promises use chaining with then and catch but async await syntax is more in synchronous way. It makes it easier to read. Error handling for async await is more straightforward when it leverages try...catch block. This is a question that you can easily get at the interview. During the answer, you can get deeper into the description of both and highlight those differences.

Promise features

Of course, you can use all the features with async await. For example Promise.all.

const fetchAllData = async () => {
    try {
        // Use await with Promise.all to fetch multiple JSON files in parallel
        const [techItems, scienceItems, laptopDetails] = await Promise.all([
            getJSON('technology_items.json'),
            getJSON('science_items.json'),
            getJSON('laptops_details.json')
        ]);

        console.log('Fetched technology items:', techItems);
        console.log('Fetched science items:', scienceItems);
        console.log('Fetched laptop details:', laptopDetails);
    } catch (error) {
        console.error('An error occurred:', error.message);
    }
};

Practical use cases

Promises are a fundamental feature in JavaScript for handling asynchronous code. Here are the main ways it is used:

Fetching Data from APIs

As was already shown in the examples above, this is one of the most used use cases for Promises and you work with it daily.

Handling file operations

Reading and writing files asynchronously can be done using promises, especially by Node.js module fs.promises

import * as fs from 'fs/promises';

const writeFileAsync = async (filePath, content, options = {}) => {
    try {
        await fs.writeFile(filePath, content, options);
        console.log(`File successfully written to ${filePath}`);
    } catch (error) {
        console.error(`Error writing file to ${filePath}:`, error.message);
    }
};

const filePath = 'output.txt';
const fileContent = 'Hello, this is some content to write to the file!';
const fileOptions = { encoding: 'utf8', flag: 'w' }; // Optional file write options

writeFileAsync(filePath, fileContent, fileOptions);

Promise based libraries

Axios is library that you should be familiar with. Axios handles HTTP requests in client and is vastly used.

Express is a web framework for Node.js. It makes it easy to build web apps and APIs, and when you use promises with Express, your code stays clean and easy to manage.

Repository with examples

All the examples can be found at: https://github.com/PrincAm/promise-example

Summary

Promises are a fundamental part of JavaScript, essential for handling asynchronous tasks in web development. Whether fetching data, working with files, or using popular libraries like Axios and Express, you’ll frequently use promises in your code.

In this article, we explored what Promises are, how to define and retrieve their results, and how to handle errors effectively. We also covered key features like chaining, Promise.all, and Promise.race. Finally, we introduced async await syntax, which offers a more straightforward way to work with promises.

Understanding these concepts is crucial for any JavaScript developer, as they are tools you’ll rely on daily.

If you haven’t tried it yet, I recommend writing a simple code snippet to fetch data from an API. You can start with a fun API to experiment with. Plus, all the examples and code snippets are available in this repository for you to explore.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn