JavaScript En boucle avec async attendent


Exemple

Lors de l'utilisation de l'attente async dans les boucles, vous pouvez rencontrer certains de ces problèmes.

Si vous essayez simplement d'utiliser forEach intérieur de forEach , cela forEach une erreur de Unexpected token .

(async() => {
 data = [1, 2, 3, 4, 5];
 data.forEach(e => {
   const i = await somePromiseFn(e);
   console.log(i);
 });
})();

Cela vient du fait que vous avez vu à tort la fonction de flèche comme un bloc. L' await sera dans le contexte de la fonction de rappel, qui n'est pas async .
L'interpréteur nous protège de l'erreur ci-dessus, mais si vous ajoutez async au rappel forEach aucune erreur ne sera forEach . Vous pourriez penser que cela résout le problème, mais cela ne fonctionnera pas comme prévu.

Exemple:

(async() => {
  data = [1, 2, 3, 4, 5];
  data.forEach(async(e) => {
    const i = await somePromiseFn(e);
    console.log(i);
  });
  console.log('this will print first');
})();

Cela se produit car la fonction asynchrone de rappel ne peut que suspendre elle-même, pas la fonction asynchrone parente.

Vous pourriez écrire une fonction asyncForEach qui retourne une promesse et vous pourriez alors await asyncForEach(async (e) => await somePromiseFn(e), data ) quelque chose comme await asyncForEach(async (e) => await somePromiseFn(e), data ) En gros, vous renvoyez une promesse qui est résolue lorsque tous les callbacks sont attendus. Mais il y a de meilleures façons de le faire, et il suffit d'utiliser une boucle.

Vous pouvez utiliser une boucle for-of ou une boucle for/while while, peu importe laquelle vous choisissez.

(async() => {
  data = [1, 2, 3, 4, 5];
  for (let e of data) {
    const i = await somePromiseFn(e);
    console.log(i);
  }
  console.log('this will print last');
})();

Mais il y a une autre prise. Cette solution attendra que chaque appel à somePromiseFn se termine avant de l'itérer sur le suivant.
C'est génial si vous voulez que vos somePromiseFn à somePromiseFn soient exécutés dans l'ordre, mais si vous voulez qu'ils s'exécutent simultanément, vous devrez await sur Promise.all .

(async() => {
 data = [1, 2, 3, 4, 5];
 const p = await Promise.all(data.map(async(e) => await somePromiseFn(e)));
 console.log(...p);
})();

Promise.all reçoit un tableau de promesses comme seul paramètre et renvoie une promesse. Lorsque toutes les promesses du tableau sont résolues, la promesse renvoyée est également résolue. Nous await cette promesse et quand elle sera résolue, toutes nos valeurs seront disponibles.

Les exemples ci-dessus sont entièrement exécutables. La fonction somePromiseFn peut être somePromiseFn comme une fonction d'écho asynchrone avec un délai d'attente. Vous pouvez essayer les exemples dans babel-repl avec au moins le preset stage-3 et regarder la sortie.

function somePromiseFn(n) {
 return new Promise((res, rej) => {
   setTimeout(() => res(n), 250);
 });
}