Bonjour, Habr! Je vous présente la traduction de l'article
«Comprendre les promesses en JavaScript» de Sukhjinder Arora.
De l'auteur de la traduction: En plus de l'auteur lui-même, j'espère que l'article vous a été utile. S'il vous plaît, si elle vous a vraiment aidé à apprendre quelque chose de nouveau par vous-même, alors ne soyez pas trop paresseux pour aller à l'article original et remercier l'auteur! Je serai heureux de vos commentaires!
Lien vers la traduction de l'article sur JavaScript asynchrone du même auteur .JavaScript est un langage de programmation monothread, ce qui signifie qu'une seule chose peut être faite à la fois. Avant ES6, nous utilisions des rappels pour gérer les tâches asynchrones, telles que les requêtes réseau.
En utilisant des promesses, nous pouvons éviter «l'enfer du rappel» et rendre notre code plus propre, plus lisible et plus facile à comprendre.
Supposons que nous voulons obtenir des données du serveur de manière asynchrone, en utilisant des rappels, nous ferions quelque chose comme ceci:
getData(function(x){ console.log(x); getMoreData(x, function(y){ console.log(y); getSomeMoreData(y, function(z){ console.log(z); }); }); });
Ici, je demande des données au serveur à l'aide de la fonction
getData () , qui reçoit des données à l'intérieur de la fonction de rappel. À l'intérieur de la fonction de rappel, je demande des données supplémentaires en appelant la fonction
getMoreData () , en passant les données précédentes en argument, etc.
C'est ce que nous appelons «l'enfer du rappel», où chaque rappel est imbriqué dans l'autre, et chaque rappel interne dépend de son parent.
Nous pouvons réécrire l'extrait ci-dessus en utilisant des promesses:
getData() .then((x) => { console.log(x); return getMoreData(x); }) .then((y) => { console.log(y); return getSomeMoreData(y); }) .then((z) => { console.log(z); });
Vous pouvez voir ce qui est devenu plus lisible qu'avec le premier exemple de rappel.
Quelles sont les promesses?
Une promesse (promesse) est un objet qui contient la valeur future d'une opération asynchrone. Par exemple, si vous demandez des données au serveur, Promis nous promet de recevoir ces données, que nous pourrons utiliser à l'avenir.
Avant de plonger dans tous ces trucs techniques, regardons la terminologie des promesses.
États promis
Une promesse en JavaScript, comme une promesse dans la vie réelle, a 3 états. Cela peut être 1) non résolu (en attente), 2) résolu / résolu (terminé) ou 3) rejeté / rejeté.
Non résolu ou en attente - Promis attend si le résultat n'est pas prêt. Autrement dit, il attend l'achèvement de quelque chose (par exemple, l'achèvement d'une opération asynchrone).
Résolu ou terminé - Promis résolu si le résultat est disponible. Autrement dit, quelque chose a terminé son exécution (par exemple, une opération asynchrone) et tout s'est bien passé.
Rejeté - Promis rejeté si une erreur s'est produite lors de l'exécution.
Maintenant que nous savons ce qu'est Promis et sa terminologie, revenons à la partie pratique des promesses.
Créer des promesses
Dans la plupart des cas, vous utiliserez simplement des promesses, pas les créerez, mais il est toujours important de savoir comment elles sont créées.
Syntaxe:
const promise = new Promise((resolve, reject) => { ... });
Nous avons créé une nouvelle promesse en utilisant le constructeur Promises, cela prend un argument, un rappel, également connu sous le nom de fonction exécutive, qui prend 2 rappels,
résoudre et
rejeter .
La fonction exécutive est exécutée immédiatement après la création de la promesse. Une promesse est faite en appelant
resolver () et rejetée par
reject () . Par exemple:
const promise = new Promise((resolve, reject) => { if(allWentWell) { resolve(' !'); } else { reject('- '); } });
resolver () et
rejeter () prennent un argument, qui peut être une chaîne, un nombre, une expression logique, un tableau ou un objet.
Jetons un coup d'œil à un autre exemple pour bien comprendre comment les promesses sont créées.
const promise = new Promise((resolve, reject) => { const randomNumber = Math.random(); setTimeout(() => { if(randomNumber < .6) { resolve(' !'); } else { reject('- '); } }, 2000); });
Ici, j'ai créé une nouvelle promesse en utilisant le constructeur Promis. Une promesse est exécutée ou rejetée 2 secondes après sa création. Une promesse est exécutée si
randomNumber est inférieur à 0,6 et rejeté dans les autres cas.
Lorsqu'une promesse a été créée, elle est en attente et sa valeur n'est pas
définie .
Après 2 secondes, le temporisateur se termine, la promesse est exécutée ou rejetée de manière aléatoire, et sa valeur sera celle transmise à la fonction de
résolution ou de
rejet . Voici un exemple de deux cas:
Achèvement réussi:

Promesse de rejet:
Remarque: la promesse ne peut être exécutée ou rejetée qu'une seule fois. D'autres appels pour
résoudre () ou
rejeter () n'affecteront en aucun cas l'état de la promesse. Un exemple:
const promise = new Promise((resolve, reject) => { resolve('Promise resolved');
Depuis que
resolver () a été appelé en premier, la promesse a maintenant le statut «terminée». L'appel ultérieur à
rejeter () n'affectera en aucun cas l'état de la promesse.
Utilisation de Promis
Maintenant, nous savons comment créer des promesses, voyons maintenant comment appliquer la promesse déjà créée. Nous utilisons des promesses en utilisant les méthodes
then () et
catch () .
Par exemple, interroger les données d'une API à l'aide de la
récupération , qui renvoie une promesse.
syntaxe .then () : promise.then (successCallback, failureCallback)successCallback est appelé si la promesse a été exécutée avec succès. Il prend un argument, qui est la valeur transmise à
resolver () .
failureCallback est appelé si la promesse a été rejetée. Il prend un argument, qui est la valeur donnée à
rejeter () .
Un exemple:
const promise = new Promise((resolve, reject) => { const randomNumber = Math.random(); if(randomNumber < .7) { resolve(' !'); } else { reject(new Error('- ')); } }); promise.then((data) => { console.log(data);
Si la promesse a été exécutée,
successCallback est
appelée avec la valeur transmise à
resolver () . Et si la promesse a été rejetée,
failCallback est
appelé avec la valeur passée à rejeter ().
Syntaxe .catch () : promise.catch (failureCallback)Nous utilisons
catch () pour gérer les erreurs. Ceci est plus lisible que la gestion des erreurs dans
failureCallback dans le rappel de la méthode
then () .
const promise = new Promise((resolve, reject) => { reject(new Error('- ')); }); promise .then((data) => { console.log(data); }) .catch((error) => { console.log(error);
Chaîne de promesse
Les méthodes
then () et
catch () peuvent également renvoyer une nouvelle promesse, qui peut être traitée par une chaîne d'autres then () à la fin de la méthode then () précédente.
Nous utilisons une chaîne de promesses lorsque nous voulons réaliser une séquence de promesses.
Par exemple:
const promise1 = new Promise((resolve, reject) => { resolve('Promise1 '); }); const promise2 = new Promise((resolve, reject) => { resolve('Promise2 '); }); const promise3 = new Promise((resolve, reject) => { reject('Promise3 '); }); promise1 .then((data) => { console.log(data);
Alors qu'est-ce qui se passe ici?
Lorsque la
promesse1 est remplie, la méthode
then () est appelée
, qui renvoie la promesse2.
Ensuite, lorsque la
promesse2 est
remplie ,
() est à nouveau appelé et renvoie la
promesse3 .
Puisque promise3 est rejeté, au lieu du suivant
alors () ,
catch () est appelé, qui gère le rejet de
promise3 .
Remarque: En règle générale, une méthode
catch () suffit pour gérer le rejet de l'une des promesses de la chaîne, si cette méthode est à la fin.
Erreur courante
Beaucoup de nouveaux arrivants font une erreur en investissant des promesses à l'intérieur des autres. Par exemple:
const promise1 = new Promise((resolve, reject) => { resolve('Promise1 '); }); const promise2 = new Promise((resolve, reject) => { resolve('Promise2 '); }); const promise3 = new Promise((resolve, reject) => { reject('Promise3 '); }); promise1.then((data) => { console.log(data);
Bien que cela fonctionne correctement, il est considéré comme un mauvais style et rend le code moins lisible. Si vous avez une séquence de promesses à exécuter, il vaudra mieux les mettre l'une après l'autre que de les mettre l'une dans l'autre.
Promise.all ()
Cette méthode prend un tableau de promesses et renvoie une nouvelle promesse qui sera exécutée lorsque toutes les promesses à l'intérieur du tableau seront exécutées ou rejetées dès qu'une promesse rejetée sera trouvée. Par exemple:
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise1 '); }, 2000); }); const promise2 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise2 '); }, 1500); }); Promise.all([promise1, promise2]) .then((data) => console.log(data[0], data[1])) .catch((error) => console.log(error));
Ici, l'argument à l'intérieur de
then () est un tableau qui contient les valeurs des promesses dans le même ordre dans lequel elles ont été passées à
Promise.all () . (Seulement si toutes les promesses sont exécutées)
La promesse est rejetée avec la cause du rejet de la première promesse dans le tableau transféré. Par exemple:
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise1 '); }, 2000); }); const promise2 = new Promise((resolve, reject) => { setTimeout(() => { reject('Promise2 '); }, 1500); }); Promise.all([promise1, promise2]) .then((data) => console.log(data[0], data[1])) .catch((error) => console.log(error));
Ici, nous avons deux promesses, où l'une est exécutée après 2 secondes et l'autre s'écarte après 1,5 seconde. Dès que la deuxième promesse est rejetée, la
promesse renvoyée par
Promise.all () est rejetée sans attendre la première.
Cette méthode peut être utile lorsque vous avez plusieurs promesses et que vous souhaitez savoir quand toutes les promesses sont terminées. Par exemple, si vous demandez des données à une API tierce et que vous souhaitez faire quelque chose avec ces données uniquement lorsque toutes les demandes ont abouti.
Par conséquent, nous avons
Promise.all () , qui attend l'exécution réussie de toutes les promesses, ou termine son exécution lorsqu'il détecte le premier échec dans le tableau de promesses.
Promise.race ()
Cette méthode accepte un tableau de promesses et renvoie une nouvelle promesse qui sera exécutée dès que la promesse remplie dans le tableau sera remplie ou rejetée si la promesse rejetée se produit plus tôt. Par exemple:
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise1 '); }, 1000); }); const promise2 = new Promise((resolve, reject) => { setTimeout(() => { reject('Promise2 '); }, 1500); }); Promise.race([promise1, promise2]) .then((data) => console.log(data))
Ici, nous avons deux promesses, où l'une est exécutée après 1 seconde et l'autre s'écarte après 1,5 seconde. Dès que la première promesse est remplie, la promesse renvoyée par Promise.race () aura le statut rempli sans attendre le statut de la deuxième promesse.
Ici, les
données qui sont passées à
then () sont la valeur de la première promesse exécutée.
Par conséquent,
Promise.race () attend la première promesse et prend son statut comme le statut de la promesse retournée.
Commentaire de l'auteur de la traduction: D'où le nom lui-même. Race - RaceConclusion
Nous avons appris quelles sont les promesses et ce qu'elles mangent en JavaScript. Les promesses se composent de deux parties 1) Créez une promesse et 2) Utilisez une promesse. La plupart du temps, vous utiliserez des promesses plutôt que de les créer, mais il est important de savoir comment elles sont créées.
C'est tout, j'espère que cet article vous a été utile!