Comment travailler avec async / wait dans les boucles JavaScript

Comment exécuter des boucles asynchrones dans l'ordre ou en parallèle en JavaScript?


Avant de faire de la magie asynchrone, je veux vous rappeler à quoi ressemblent les boucles synchrones classiques.


Boucles synchrones


Il y a longtemps, j'ai écrit des boucles de cette façon (peut-être vous aussi):


for (var i=0; i < array.length; i++) { var item = array[i]; //  -  item } 

Ce cycle est bon et rapide. Mais il a beaucoup de problèmes de lisibilité et de support. Après un certain temps, je me suis habitué à sa meilleure version:


 array.forEach((item) => { //  -  item }); 

JavaScript se développe très rapidement. De nouvelles fonctionnalités et syntaxe apparaissent. Une de mes améliorations préférées est async / wait .


Maintenant, j'utilise assez souvent cette syntaxe. Et parfois, il y a des situations où j'ai besoin de faire quelque chose avec des éléments de tableau de manière asynchrone.


Boucles asynchrones


Comment utiliser l' await dans le corps de la boucle? Essayons simplement d'écrire une fonction asynchrone et attendons la tâche de traiter chaque élément:


 async function processArray(array) { array.forEach(item => { //       //     ! await func(item); }) } 

Ce code générera une erreur. Pourquoi? Parce que nous ne pouvons pas utiliser await dans une fonction synchrone. Comme vous pouvez le voir, processArray est une fonction asynchrone. Mais la fonction anonyme que nous utilisons pour forEach est synchrone .


Que peut-on faire à ce sujet?


1. N'attendez pas le résultat de l'exécution


Nous pouvons définir une fonction anonyme comme asynchrone:


 async function processArray(array) { array.forEach(async (item) => { await func(item); }) console.log('Done!'); } 

Mais forEach n'attendra pas la fin de la tâche. forEach est une opération synchrone. Elle va simplement lancer les tâches et passer à autre chose. Vérifions un test simple:


 function delay() { return new Promise(resolve => setTimeout(resolve, 300)); } async function delayedLog(item) { //    await  Promise //    delay await delay(); console.log(item); } async function processArray(array) { array.forEach(async (item) => { await delayedLog(item); }) console.log('Done!'); } processArray([1, 2, 3]); 

Dans la console, nous verrons:


 Done! 1 2 3 

Dans certaines situations, cela peut être un résultat normal. Mais encore, dans la plupart des cas, ce n'est pas une logique appropriée.


2. Traitement séquentiel du cycle


Afin d'attendre le résultat de l'exécution du corps de la boucle, nous devons revenir à la bonne vieille boucle "for". Mais cette fois, nous utiliserons sa nouvelle version avec la construction for..of (Merci au protocole d'itération ):


 async function processArray(array) { for (const item of array) { await delayedLog(item); } console.log('Done!'); } 

Cela nous donnera le résultat attendu:


 1 2 3 Done! 

Chaque élément du tableau sera traité séquentiellement. Mais nous pouvons exécuter la boucle en parallèle!


3. Traitement de la boucle en parallèle


Vous devez légèrement modifier le code pour démarrer les opérations en parallèle:


 async function processArray(array) { //  "map"    const promises = array.map(delayedLog); //       await Promise.all(promises); console.log('Done!'); } 

Ce code peut exécuter plusieurs tâches delayLog en parallèle. Mais soyez prudent avec les grands tableaux. Trop de tâches peuvent être trop difficiles pour le CPU et la mémoire.


De même, veuillez ne pas confondre les "tâches parallèles" de l'exemple avec un vrai parallélisme et des threads. Ce code ne garantit pas l'exécution parallèle. Tout dépend du corps de la boucle (dans l'exemple, c'est du delayedLog ). Les demandes de réseau, les travailleurs Web et certaines autres tâches peuvent être effectuées en parallèle.

Source: https://habr.com/ru/post/fr435084/


All Articles