Maison > interface Web > js tutoriel > Comment utiliser async/await dans les boucles JavaScript ? A quoi dois-je faire attention ?

Comment utiliser async/await dans les boucles JavaScript ? A quoi dois-je faire attention ?

青灯夜游
Libérer: 2020-11-30 18:16:11
avant
5030 Les gens l'ont consulté

Comment utiliser async/await dans les boucles JavaScript ? A quoi dois-je faire attention ?

async et await sont relativement simples à utiliser. Mais les choses deviennent un peu plus compliquées lorsque vous essayez d'utiliser await dans une boucle.

Dans cet article, partagez quelques problèmes à noter lors de l'utilisation de await dans des boucles if.

Préparez un exemple

Pour cet article, disons que vous souhaitez obtenir le nombre de fruits d'une corbeille de fruits.

const fruitBasket = {
 apple: 27,
 grape: 0,
 pear: 14
};
Copier après la connexion

Vous souhaitez obtenir la quantité de chaque fruit de fruitBasket. Pour obtenir le nombre de fruits, vous pouvez utiliser la fonction getNumFruit.

const getNumFruit = fruit => {
  return fruitBasket[fruit];
};

const numApples = getNumFruit('apple');
console.log(numApples); //27
Copier après la connexion

Maintenant, en supposant que fruitBasket soit obtenu du serveur, nous utilisons ici setTimeout pour simuler.

const sleep = ms => {
  return new Promise(resolve => setTimeout(resolve, ms))
};

const getNumFruie = fruit => {
  return sleep(1000).then(v => fruitBasket[fruit]);
};

getNumFruit("apple").then(num => console.log(num)); // 27
Copier après la connexion

Enfin, disons que vous souhaitez utiliser await et getNumFruit pour obtenir la quantité de chaque fruit dans une fonction asynchrone.

const control = async _ => {
  console.log('Start')

  const numApples = await getNumFruit('apple');
  console.log(numApples);

  const numGrapes = await getNumFruit('grape');
  console.log(numGrapes);

  const numPears = await getNumFruit('pear');
  console.log(numPears);

  console.log('End')
}
Copier après la connexion

Comment utiliser async/await dans les boucles JavaScript ? A quoi dois-je faire attention ?

Utilisez wait

dans la boucle for Définissez d'abord un tableau pour stocker les fruits :

const fruitsToGet = [“apple”, “grape”, “pear”];
Copier après la connexion

. loop Parcourez ce tableau :

const forLoop = async _ => {
  console.log('Start');
  
  for (let index = 0; index <p>Dans la boucle <code>for</code>, utilisez <code>getNumFruit</code> pour obtenir le numéro de chaque fruit et imprimez le numéro sur la console. </p><p>Puisque <code>getNumFruit</code> renvoie un <code>promise</code>, nous utilisons <code>await</code> pour attendre que le résultat revienne et l'imprime. </p><pre class="brush:php;toolbar:false">const forLoop = async _ => {
  console.log('start');

  for (let index = 0; index <p>Lorsque vous utilisez <code>await</code>, vous souhaitez que JavaScript suspende l'exécution jusqu'à ce qu'il attende le retour de la promesse. Cela signifie que le <code>for</code> dans la boucle <code>await</code> doit être exécuté séquentiellement. </p><p>Les résultats sont tels que vous vous en doutez. </p><pre class="brush:php;toolbar:false">“Start”;
“Apple: 27”;
“Grape: 0”;
“Pear: 14”;
“End”;
Copier après la connexion

Comment utiliser async/await dans les boucles JavaScript ? A quoi dois-je faire attention ?

Ce comportement fonctionne pour la plupart des boucles (comme les boucles while et for-of)...

mais il ne gère pas les boucles qui nécessitent des rappels, tels que forEach, map, filter et reduce. Dans les prochaines sections, nous verrons comment await affecte forEach, la carte et filter.

Utilisez wait

dans la boucle forEach Tout d'abord, utilisez forEach pour parcourir le tableau.

const forEach = _ => {
  console.log('start');

  fruitsToGet.forEach(fruit => {
    //...
  })

  console.log('End')
}
Copier après la connexion

Ensuite, nous essaierons d'utiliser getNumFruit pour obtenir le nombre de fruits. (Notez le mot-clé async dans la fonction de rappel. Nous avons besoin de ce mot-clé async car await est dans la fonction de rappel).

const forEachLoop = _ => {
  console.log('Start');

  fruitsToGet.forEach(async fruit => {
    const numFruit = await getNumFruit(fruit);
    console.log(numFruit)
  });

  console.log('End')
}
Copier après la connexion

Je m'attendais à ce que la console affiche ce qui suit :

“Start”;
“27”;
“0”;
“14”;
“End”;
Copier après la connexion

Mais le résultat réel est différent. Avant d'attendre que le résultat soit renvoyé dans la boucle forEach, JavaScript exécute d'abord console.log('End').

L'impression réelle de la console est la suivante :

‘Start’
‘End’
‘27’
‘0’
‘14’
Copier après la connexion

Comment utiliser async/await dans les boucles JavaScript ? A quoi dois-je faire attention ?

forEach en JavaScript ne prend pas en charge la sensibilisation aux promesses, mais prend également en charge async et await, donc impossible d'utiliser forEach à l'intérieur de await.

Utilisez wait

dans la carte Si vous utilisez map dans await, map renvoie toujours le tableau promise C'est à cause des fonctions asynchrones. toujours Oui renvoie promise.

const mapLoop = async _ => {
  console.log('Start')
  const numFruits = await fruitsToGet.map(async fruit => {
    const numFruit = await getNumFruit(fruit);
    return numFruit;
  })
  
  console.log(numFruits);

  console.log('End')
}
      

“Start”;
“[Promise, Promise, Promise]”;
“End”;
Copier après la connexion

Comment utiliser async/await dans les boucles JavaScript ? A quoi dois-je faire attention ?

Si vous utilisez map à l'intérieur de await, map renvoie toujours promises et vous devez attendre que le tableau promises soit traité. Ou faites-le via await Promise.all(arrayOfPromises).

const mapLoop = async _ => {
  console.log('Start');

  const promises = fruitsToGet.map(async fruit => {
    const numFruit = await getNumFruit(fruit);
    return numFruit;
  });

  const numFruits = await Promise.all(promises);
  console.log(numFruits);

  console.log('End')
}
Copier après la connexion

Le résultat d'exécution est le suivant :

Comment utiliser async/await dans les boucles JavaScript ? A quoi dois-je faire attention ?

Si vous le souhaitez, vous pouvez traiter la valeur de retour dans promise, et la valeur analysée sera la valeur renvoyée.

const mapLoop = _ => {
  // ...
  const promises = fruitsToGet.map(async fruit => {
    const numFruit = await getNumFruit(fruit);
    return numFruit + 100
  })
  // ...
}
 
“Start”;
“[127, 100, 114]”;
“End”;
Copier après la connexion

Utiliser wait

dans la boucle de filtre Lorsque vous utilisez filter, vous souhaitez filtrer le tableau avec des résultats spécifiques. Supposons que vous filtrez un tableau dont le nombre est supérieur à 20.

Si vous utilisez filter normalement (sans attendre), comme suit :

const filterLoop =  _ => {
  console.log('Start')

  const moreThan20 =  fruitsToGet.filter(async fruit => {
    const numFruit = await fruitBasket[fruit]
    return numFruit > 20
  })
  
  console.log(moreThan20) 
  console.log('END')
}
Copier après la connexion

Le résultat de l'exécution de

Start
["apple"]
END
Copier après la connexion

filter ne sera pas de la même manière. En fait, ça ne marche pas du tout. await

const filterLoop = async _ => {
  console.log('Start')

  const moreThan20 =  await fruitsToGet.filter(async fruit => {
    const numFruit = fruitBasket[fruit]
    return numFruit > 20
  })
  
  console.log(moreThan20) 
  console.log('END')
}


// 打印结果
Start
["apple", "grape", "pear"]
END
Copier après la connexion

Comment utiliser async/await dans les boucles JavaScript ? A quoi dois-je faire attention ?

Pourquoi cela se produit-il

Lorsque vous utilisez

dans un rappel filter, le rappel est toujours un await. Puisque promise est toujours vrai, tous les éléments du tableau passent par promise. Utilisez le code suivant dans filter en utilisant la filter classeawait

const filtered = array.filter(true);
Copier après la connexion

filter使用 await 正确的三个步骤

  1. 使用map返回一个promise 数组
  2. 使用 await 等待处理结果
  3. 使用 filter 对返回的结果进行处理
const filterLoop = async _ => {
  console.log('Start');

  const promises = await fruitsToGet.map(fruit => getNumFruit(fruit));
 
  const numFruits = await Promise.all(promises);

  const moreThan20 = fruitsToGet.filter((fruit, index) => {
    const numFruit = numFruits[index];
    return numFruit > 20;
  })

  console.log(moreThan20);
  console.log('End')
}
Copier après la connexion

Comment utiliser async/await dans les boucles JavaScript ? A quoi dois-je faire attention ?

在 reduce 循环中使用 await

如果想要计算 fruitBastet中的水果总数。 通常,你可以使用reduce循环遍历数组并将数字相加。

const reduceLoop = _ => {
  console.log('Start');

  const sum = fruitsToGet.reduce((sum, fruit) => {
    const numFruit = fruitBasket[fruit];
    return sum + numFruit;
  }, 0)

  console.log(sum)
  console.log('End')
}
Copier après la connexion

运行结果:

Comment utiliser async/await dans les boucles JavaScript ? A quoi dois-je faire attention ?

当你在 reduce 中使用await时,结果会变得非常混乱。

 const reduceLoop = async _ => {
  console.log('Start');

  const sum = await fruitsToGet.reduce(async (sum, fruit) => {
    const numFruit = await fruitBasket[fruit];
    return sum + numFruit;
  }, 0)

  console.log(sum)
  console.log('End')
}
Copier après la connexion

Comment utiliser async/await dans les boucles JavaScript ? A quoi dois-je faire attention ?

[object Promise]14 是什么 鬼??

剖析这一点很有趣。

  1. 在第一次遍历中,sum0numFruit27(通过getNumFruit(apple)的得到的值),0 + 27 = 27
  2. 在第二次遍历中,sum是一个promise。 (为什么?因为异步函数总是返回promises!)numFruit0.promise 无法正常添加到对象,因此JavaScript将其转换为[object Promise]字符串。 [object Promise] + 0object Promise] 0
  3. 在第三次遍历中,sum 也是一个promisenumFruit14. [object Promise] + 14[object Promise] 14

解开谜团!

这意味着,你可以在reduce回调中使用await,但是你必须记住先等待累加器!

const reduceLoop = async _ => {
  console.log('Start');

  const sum = await fruitsToGet.reduce(async (promisedSum, fruit) => {
    const sum = await promisedSum;
    const numFruit = await fruitBasket[fruit];
    return sum + numFruit;
  }, 0)

  console.log(sum)
  console.log('End')
}
Copier après la connexion

Comment utiliser async/await dans les boucles JavaScript ? A quoi dois-je faire attention ?

但是从上图中看到的那样,await 操作都需要很长时间。 发生这种情况是因为reduceLoop需要等待每次遍历完成promisedSum

有一种方法可以加速reduce循环,如果你在等待promisedSum之前先等待getNumFruits(),那么reduceLoop只需要一秒钟即可完成:

const reduceLoop = async _ => {
  console.log('Start');

  const sum = await fruitsToGet.reduce(async (promisedSum, fruit) => {
    const numFruit = await fruitBasket[fruit];
    const sum = await promisedSum;
    return sum + numFruit;
  }, 0)

  console.log(sum)
  console.log('End')
}
Copier après la connexion

1Comment utiliser async/await dans les boucles JavaScript ? A quoi dois-je faire attention ?

这是因为reduce可以在等待循环的下一个迭代之前触发所有三个getNumFruit promise。然而,这个方法有点令人困惑,因为你必须注意等待的顺序。

在reduce中使用wait最简单(也是最有效)的方法是

  1. 使用map返回一个promise 数组
  2. 使用 await 等待处理结果
  3. 使用 reduce 对返回的结果进行处理

    const reduceLoop = async _ => {
     console.log('Start');

    const promises = fruitsToGet.map(getNumFruit);
     const numFruits = await Promise.all(promises);
     const sum = numFruits.reduce((sum, fruit) => sum + fruit);

    console.log(sum)
     console.log('End')
    }

这个版本易于阅读和理解,需要一秒钟来计算水果总数。

1Comment utiliser async/await dans les boucles JavaScript ? A quoi dois-je faire attention ?

从上面看出来什么

  1. 如果你想连续执行await调用,请使用for循环(或任何没有回调的循环)。
  2. 永远不要和forEach一起使用await,而是使用for循环(或任何没有回调的循环)。
  3. 不要在 filterreduce 中使用 await,如果需要,先用 map 进一步骤处理,然后在使用 filterreduce 进行处理。

原文地址:https://medium.com/free-code-camp/javascript-async-and-await-in-loops-30ecc5fb3939 

更多编程相关知识,请访问:编程学习网站!!

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!

Étiquettes associées:
source:segmentfault.com
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal