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.
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 };
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
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
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') }
dans la boucle for Définissez d'abord un tableau pour stocker les fruits :
const fruitsToGet = [“apple”, “grape”, “pear”];
. 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”;
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
.
dans la boucle forEach Tout d'abord, utilisez forEach
pour parcourir le tableau.
const forEach = _ => { console.log('start'); fruitsToGet.forEach(fruit => { //... }) console.log('End') }
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') }
Je m'attendais à ce que la console affiche ce qui suit :
“Start”; “27”; “0”; “14”; “End”;
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’
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
.
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”;
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') }
Le résultat d'exécution est le suivant :
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”;
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') }
Le résultat de l'exécution de
Start ["apple"] END
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
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);
在filter
使用 await
正确的三个步骤
map
返回一个promise 数组await
等待处理结果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') }
如果想要计算 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') }
运行结果:
当你在 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') }
[object Promise]14
是什么 鬼??
剖析这一点很有趣。
sum
为0
。numFruit
是27
(通过getNumFruit(apple)
的得到的值),0 + 27 = 27
。sum
是一个promise
。 (为什么?因为异步函数总是返回promises
!)numFruit
是0
.promise 无法正常添加到对象,因此JavaScript将其转换为[object Promise]
字符串。 [object Promise] + 0
是object Promise] 0
。sum
也是一个promise
。 numFruit
是14
. [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') }
但是从上图中看到的那样,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') }
这是因为reduce
可以在等待循环的下一个迭代之前触发所有三个getNumFruit
promise。然而,这个方法有点令人困惑,因为你必须注意等待的顺序。
在reduce中使用wait最简单(也是最有效)的方法是
map
返回一个promise 数组await
等待处理结果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')
}
这个版本易于阅读和理解,需要一秒钟来计算水果总数。
await
调用,请使用for
循环(或任何没有回调的循环)。forEach
一起使用await
,而是使用for
循环(或任何没有回调的循环)。filter
和 reduce
中使用 await
,如果需要,先用 map
进一步骤处理,然后在使用 filter
和 reduce
进行处理。原文地址: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!