async
etawait
sont relativement simples à utiliser. Mais les choses deviennent un peu plus compliquées lorsque vous essayez d'utiliserawait
dans une boucle.
Dans cet article, partagez quelques problèmes à noter lors de l'utilisation deawait
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 defruitBasket
. Pour obtenir le nombre de fruits, vous pouvez utiliser la fonctiongetNumFruit
.
const getNumFruit = fruit => { return fruitBasket[fruit]; }; const numApples = getNumFruit('apple'); console.log(numApples); //27
Maintenant, en supposant quefruitBasket
soit obtenu du serveur, nous utilisons icisetTimeout
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 utiliserawait
etgetNumFruit
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; indexDans la boucle
for
, utilisezgetNumFruit
pour obtenir le numéro de chaque fruit et imprimez le numéro sur la console.Puisque
getNumFruit
renvoie unpromise
, nous utilisonsawait
pour attendre que le résultat revienne et l'imprime.const forLoop = async _ => { console.log('start'); for (let index = 0; indexLorsque vous utilisez
await
, vous souhaitez que JavaScript suspende l'exécution jusqu'à ce qu'il attende le retour de la promesse. Cela signifie que lefor
dans la boucleawait
doit être exécuté séquentiellement.Les résultats sont tels que vous vous en doutez.
“Start”; “Apple: 27”; “Grape: 0”; “Pear: 14”; “End”;Copier après la connexion
Ce comportement fonctionne pour la plupart des boucles (comme les boucleswhile
etfor-of
)...
mais il ne gère pas les boucles qui nécessitent des rappels, tels queforEach
,map
,filter
etreduce
. Dans les prochaines sections, nous verrons commentawait
affecteforEach
, la carte etfilter
.
dans la boucle forEach Tout d'abord, utilisezforEach
pour parcourir le tableau.
const forEach = _ => { console.log('start'); fruitsToGet.forEach(fruit => { //... }) console.log('End') }
Ensuite, nous essaierons d'utilisergetNumFruit
pour obtenir le nombre de fruits. (Notez le mot-cléasync
dans la fonction de rappel. Nous avons besoin de ce mot-cléasync
carawait
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 boucleforEach
, 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 chargeasync
etawait
, donc impossible d'utiliserforEach
à l'intérieur deawait
.
dans la carte Si vous utilisezmap
dansawait
,map
renvoie toujours le tableaupromise
C'est à cause des fonctions asynchrones. toujours Oui renvoiepromise
.
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 utilisezmap
à l'intérieur deawait
,map
renvoie toujourspromises
et vous devez attendre que le tableaupromises
soit traité. Ou faites-le viaawait 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 danspromise
, 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 utilisezfilter
, 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 utilisezfilter
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 rappelfilter
, le rappel est toujours unawait
. Puisquepromise
est toujours vrai, tous les éléments du tableau passent parpromise
. Utilisez le code suivant dansfilter
en utilisant lafilter
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!