Rappels JavaScript, promesses et fonctions asynchrones partie 2

introduction

Dans la première partie de ce didacticiel, nous avons appris les principes de la programmation asynchrone et de l'utilisation de rappels. En résumé, la programmation asynchrone nous permet d’écrire du code non bloquant en exécutant des tâches de blocage ultérieurement. Les fonctions de rappel fournissent un moyen de synchroniser l'exécution de notre code. 

Cependant, l'imbrication répétée des rappels n'est pas un bon modèle à suivre. Voici des promesses à la rescousse. Les promesses sont utilisées depuis longtemps dans les bibliothèques JavaScript, mais vous pouvez maintenant les utiliser de manière native dans votre code. Les fonctions asynchrones améliorent les promesses en nous permettant d’écrire nos tâches l’une après l’autre sans que nous ayons à nous soucier du moment de leur exécution..

Contenu

  • Promesses
  • Fonctions asynchrones
  • La revue
  • Ressources

Promesses

Jetons un coup d'oeil à ce qu'une promesse est conceptuellement. Imaginez le cas où vous effectuez des achats en ligne et achetez une paire de chaussures. Lorsque vous validez votre commande, un résumé de votre achat vous est envoyé par courrier électronique.. 

Cette confirmation de commande est comme une promesse. La promesse est votre garantie que vous obtiendrez quelque chose ultérieurement de la part de la société. Bien que votre commande soit en attente, votre vie ne s’arrête pas, bien sûr. Vous continuez à effectuer d'autres tâches, telles que la navigation sur Internet. Si votre commande est remplie, vous recevrez un email avec les informations de livraison. Il est possible que votre commande soit rejetée. L'article que vous avez commandé est peut-être en rupture de stock ou il pourrait y avoir un problème avec votre mode de paiement. Dans ce cas, vous recevrez un email vous informant de l'erreur..

En langage de code, une promesse est un objet qui garantit que nous obtiendrons une valeur future pour notre demande, qu'elle aboutisse ou non. C'est la forme générale pour créer et utiliser une promesse:

function tâche1 () retourne la nouvelle promesse (function (résoudre, rejeter) résoudre (données); rejeter (erreur););  task1 () .then (function (result) console.log (result);) .catch (function (error) console.log (error););

Pour créer une promesse, vous instanciez un objet de promesse et écrivez votre code asynchrone dans la fonction de rappel de la promesse. Les données que vous voulez renvoyer de la promesse sont transmises en tant qu’argument au résoudre fonction, et votre message d'erreur est passé dans le rejeter une fonction. Nous enchaînons des promesses en utilisant le puis méthode. Cela nous permet d'exécuter les tâches de manière séquentielle. 

Si nous devons passer les résultats d’une tâche à la tâche suivante, nous le renvoyons dans le puis méthode. Nous pouvons vouloir enchaîner les promesses lorsque nous sommes intéressés à transformer des valeurs ou que nous devons exécuter notre code dans un ordre particulier. Au bout de la chaîne, nous rattrapons nos erreurs. Si une erreur survient dans l’une de nos tâches, les tâches restantes sont ignorées et l’erreur est envoyée à notre bloc catch..

Dans la première partie de ce didacticiel, nous avons utilisé des rappels pour ouvrir un fichier et récupérer un message et ses commentaires. Voici à quoi ressemble le code complet en utilisant des promesses:

index.js

const fs = require ('fs'); const path = require ('path'); const postsUrl = path.join (__ dirname, 'db / posts.json'); const commentsUrl = path.join (__ dirname, 'db / comments.json'); // retourne les données de notre fichier function loadCollection (url) retourne une nouvelle promesse (fonction (résoudre, rejeter) fs.readFile (url, 'utf8', fonction (erreur, données) if (erreur) rejette (' erreur '); else résoudre (JSON.parse (données));););  // retourne un objet par id function getRecord (collection, id) retour nouvelle Promise (fonction (résoudre, rejeter) const data = collection.find (fonction (element) return element.id == id;); résoudre (données););  // retourne un tableau de commentaires pour une fonction post getCommentsByPost (comments, postId) return comments.filter (function (comment) return, comment.postId == postId;);  // code d'initialisation loadCollection (postsUrl) .then (function (posts) return getRecord (posts, "001");) .then (function (post) console.log (post); return loadCollection (commentsUrl); ) .then (function (comments) const postComments = getCommentsByPost (comments, "001"); console.log (postComments);) .catch (function (erreur) console.log (erreur););

La différence ici est que notre méthode pour ouvrir le fichier est maintenant encapsulée dans un objet de promesse. Et au lieu de lier nos tâches à des rappels, elles sont enchaînées avec puis

Comme vous pouvez le constater, nous n’avons pas éliminé le besoin de rappels. Nous les utilisons simplement différemment. Avant, nous imbriquions nos rappels afin de pouvoir continuer l'exécution de notre code dans la tâche suivante.. 

Cela me rappelle lorsque j'appelle le service clientèle à propos d'un problème et qu'au lieu que l'agent résolve mon problème, je suis transféré à quelqu'un d'autre. Que quelqu'un d'autre puisse ou non résoudre l'appel, mais en ce qui concerne le premier agent, c'est la responsabilité de quelqu'un d'autre. 

Avec des promesses, nous allons récupérer quelque chose avant de passer à la tâche suivante. Si nous devons porter cela quelque chose à la suite de notre code, nous pouvons utiliser un puis déclaration.

Tâche

À l'aide de promesses, écrivez un programme qui ouvrira un fichier d'utilisateurs, obtiendra les informations de l'utilisateur, puis ouvrira un fichier de messages et imprimera tous les messages de l'utilisateur..

Fonctions asynchrones

Les promesses représentent une amélioration dans la conception de notre programme, mais nous pouvons faire mieux. Ce serait très pratique si nous pouvions exécuter nos tâches de manière synchrone comme ceci:

tache 1(); task2 (); task3 ();

Eh bien, nous pouvons avec le modèle async / wait. Pour ce faire, nous commençons par envelopper nos tâches dans une fonction asynchrone. Cette fonction renvoie une promesse. Ensuite, nous implémentons la gestion des erreurs en encapsulant nos tâches dans un essayer / attraper déclaration. 

Si la promesse est remplie, elle accomplira toutes les tâches à l'intérieur de notre essayer bloc. Si elle est rejetée, le capture le bloc sera exécuté. Ajout du attendre mot-clé avant toute tâche met notre programme en pause jusqu'à ce que la tâche se termine. 

Voici la forme générale d'utilisation des fonctions asynchrones:

fonction async. initTasks () try const a = wait task1 (); const b = wait task2 (); const c = wait task3 (); // faire quelque chose avec a, b et c catch (error) // faire quelque chose avec l'objet error initTasks ();

En utilisant ce modèle, nous pouvons réécrire la façon dont nous exécutons notre code dans notre exemple de fichiers..

fonction asynchrone getPost () try const posts = wait loadCollection (postsUrl); const post = wait getRecord (posts, "001"); const comments = wait loadCollection (commentsUrl); const postComments = wait getCommentsByPost (comments, post.id); console.log (post); console.log (postComments);  catch (error) console.log (error);  getPost ();

J'aime structurer notre code asynchrone avec un essayer / attraper instruction car elle sépare clairement le code de traitement des erreurs du code normal. Si l'un des codes de notre essayer bloc provoque une erreur, elle sera gérée par le capture bloc. De plus, nous pouvons ajouter un enfin bloquer qui exécutera le code indépendamment du fait que nos tâches réussissent ou échouent. 

Un exemple d'utilisation de ce modèle est lorsque nous avons le code de nettoyage à exécuter. Ce code ne doit pas nécessairement être contenu dans un enfin bloc. Il peut être écrit après le capture déclaration, et il va exécuter. Les promesses n'ont pas cette syntaxe intégrée. Nous devrions en chaîner une autre puis déclaration après notre capture déclaration pour obtenir le même effet.

Tâche

En utilisant async / wait, écrivez un programme qui ouvrira un fichier d'utilisateurs, obtiendra les informations de l'utilisateur, puis ouvrira un fichier de messages et imprimera les informations de l'utilisateur et tous ses messages..

La revue

Les rappels ne sont pas pervers par nature. Passer des fonctions à d'autres fonctions est un modèle utile en JavaScript. Les rappels deviennent un problème lorsque nous les utilisons pour contrôler le flux de notre logique d'application. Comme JavaScript est asynchrone, nous devons prendre soin de la façon dont nous écrivons notre code car les tâches ne se termineront pas nécessairement dans l’ordre dans lequel elles ont été écrites. Ce n’est pas une mauvaise chose car nous ne voulons aucune tâche empêchant la poursuite du programme.. 

Les promesses sont un meilleur modèle pour écrire du code asynchrone. Ils ne corrigent pas seulement l'encombrement des rappels imbriqués, mais ils gardent également le contrôle du résultat d'une tâche dans la tâche. Passer le contrôle à une autre tâche, qu'il s'agisse de notre propre code ou d'une API tierce, rend notre code moins fiable. Enfin, les fonctions asynchrones nous permettent d’écrire notre code de manière synchrone, ce qui est beaucoup plus intuitif et plus facile à comprendre..

Ressources

  • Vous ne savez pas JS: Async & Performance Ch 3: Promises
  • JavaScript Promises: Une introduction
  • Fonctions asynchrones: faire des promesses amicales
  • Async / Await par Patrick Triest