async
is relatively simple to use with await
. But things get a little more complicated when you try to use await
inside a loop.
In this article, share some issues worth noting when using await
in if loops.
For this post, let’s say you want to get the number of fruits from a fruit basket.
const fruitBasket = { apple: 27, grape: 0, pear: 14 };
You want to get the quantity of each fruit from fruitBasket
. To get the number of fruits, you can use the getNumFruit
function.
const getNumFruit = fruit => { return fruitBasket[fruit]; }; const numApples = getNumFruit('apple'); console.log(numApples); //27
Now, assuming fruitBasket
is obtained from the server, here we use setTimeout
to simulate.
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
Finally, suppose you want to use await
and getNumFruit
to get the number of each fruit in an asynchronous function.
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') }
First define an array to store fruits:
const fruitsToGet = [“apple”, “grape”, “pear”];
Loop Traverse this array:
const forLoop = async _ => { console.log('Start'); for (let index = 0; indexIn the
for
loop, usegetNumFruit
to get the number of each fruit and print the number to the console.Since
getNumFruit
returns apromise
, we useawait
to wait for the result to be returned and print it.const forLoop = async _ => { console.log('start'); for (let index = 0; indexWhen using
await
, you want JavaScript to pause execution until the promise returns the processing result. This means that theawait
in thefor
loop should be executed sequentially.The results are as you would expect.
“Start”; “Apple: 27”; “Grape: 0”; “Pear: 14”; “End”;Copy after login
This behavior applies to most loops (such as while
and for-of
loops)…
But it cannot handle loops that require callbacks, such as forEach
, map
, filter
, and reduce
. In the next few sections, we'll examine how await
affects forEach
, map, and filter
.
First, use forEach
to traverse the array.
const forEach = _ => { console.log('start'); fruitsToGet.forEach(fruit => { //... }) console.log('End') }
Next, we will try to get the number of fruits using getNumFruit
. (Note the async
keyword in the callback function. We need this async
keyword because await
is in the callback function).
const forEachLoop = _ => { console.log('Start'); fruitsToGet.forEach(async fruit => { const numFruit = await getNumFruit(fruit); console.log(numFruit) }); console.log('End') }
I expected the console to print the following:
“Start”; “27”; “0”; “14”; “End”;
But the actual result is different. Before waiting for the return result in the forEach
loop, JavaScript first executes console.log('End').
The actual console print is as follows:
‘Start’ ‘End’ ‘27’ ‘0’ ‘14’
forEach
in JavaScript does not support promise awareness, but also supports async
and await
, so await
cannot be used in forEach
.
If you use await
in map
, map
always Returns an array of promise
, because asynchronous functions always return 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”;
If you use await
in map
, map
always returns promises
, you must wait for the promises
array to be processed. Or do this 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') }
The running results are as follows:
If you like, you can process the return value in promise
, and the parsed value will be returned value.
const mapLoop = _ => { // ... const promises = fruitsToGet.map(async fruit => { const numFruit = await getNumFruit(fruit); return numFruit + 100 }) // ... } “Start”; “[127, 100, 114]”; “End”;
When you use filter
, you want to filter the array with specific results. Suppose you filter an array whose number is greater than 20.
If you use filter
normally (without await), as follows:
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') }
Running results
Start ["apple"] END
filter
await
won't work the same way. In fact, it doesn't work at all.
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
Why does this happen?
When using await
in a filter
callback, The callback is always a promise
. Since promise
is always true, all items in the array pass through filter
. Use the following code in filter
await
class
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
更多编程相关知识,请访问:编程学习网站!!
The above is the detailed content of How to use async/await in JavaScript loops? What needs attention?. For more information, please follow other related articles on the PHP Chinese website!