async
및 await
는 사용이 비교적 간단합니다. 그러나 루프 내에서 await
를 사용하려고 하면 상황이 좀 더 복잡해집니다. async
与 await
的使用方式相对简单。 但当你尝试在循环中使用await
时,事情就会变得复杂一些。
在本文中,分享一些在如果循环中使用await
值得注意的问题。
对于这篇文章,假设你想从水果篮中获取水果的数量。
const fruitBasket = { apple: 27, grape: 0, pear: 14 };
你想从fruitBasket
获得每个水果的数量。 要获取水果的数量,可以使用getNumFruit
函数。
const getNumFruit = fruit => { return fruitBasket[fruit]; }; const numApples = getNumFruit('apple'); console.log(numApples); //27
现在,假设fruitBasket
是从服务器上获取,这里我们使用 setTimeout
来模拟。
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
最后,假设你想使用await
和getNumFruit
来获取异步函数中每个水果的数量。
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') }
首先定义一个存放水果的数组:
const fruitsToGet = [“apple”, “grape”, “pear”];
循环遍历这个数组:
const forLoop = async _ => { console.log('Start'); for (let index = 0; index <p>在<code>for</code>循环中,过上使用<code>getNumFruit</code>来获取每个水果的数量,并将数量打印到控制台。</p><p>由于<code>getNumFruit</code>返回一个<code>promise</code>,我们使用 <code>await</code> 来等待结果的返回并打印它。</p><pre class="brush:php;toolbar:false">const forLoop = async _ => { console.log('start'); for (let index = 0; index <p>当使用<code>await</code>时,希望JavaScript暂停执行,直到等待 promise 返回处理结果。这意味着<code>for</code>循环中的<code>await</code> 应该按顺序执行。</p><p>结果正如你所预料的那样。</p><pre class="brush:php;toolbar:false">“Start”; “Apple: 27”; “Grape: 0”; “Pear: 14”; “End”;
这种行为适用于大多数循环(比如while
和for-of
循环)…
但是它不能处理需要回调的循环,如forEach
、map
、filter
和reduce
。在接下来的几节中,我们将研究await
如何影响forEach
、map和filter
。
首先,使用 forEach
对数组进行遍历。
const forEach = _ => { console.log('start'); fruitsToGet.forEach(fruit => { //... }) console.log('End') }
接下来,我们将尝试使用getNumFruit
获取水果数量。 (注意回调函数中的async
关键字。我们需要这个async
关键字,因为await
在回调函数中)。
const forEachLoop = _ => { console.log('Start'); fruitsToGet.forEach(async fruit => { const numFruit = await getNumFruit(fruit); console.log(numFruit) }); console.log('End') }
我期望控制台打印以下内容:
“Start”; “27”; “0”; “14”; “End”;
但实际结果是不同的。在forEach
循环中等待返回结果之前,JavaScrip先执行了 console.log('End')。
实际控制台打印如下:
‘Start’ ‘End’ ‘27’ ‘0’ ‘14’
JavaScript 中的 forEach
不支持 promise 感知,也支持 async
和await
,所以不能在 forEach
使用 await
。
如果在map
中使用await
, map
始终返回promise
数组,这是因为异步函数总是返回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”;
如果你在 map
中使用 await
,map
总是返回promises
,你必须等待promises
数组得到处理。 或者通过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') }
运行结果如下:
如果你愿意,可以在promise
中处理返回值,解析后的将是返回的值。
const mapLoop = _ => { // ... const promises = fruitsToGet.map(async fruit => { const numFruit = await getNumFruit(fruit); return numFruit + 100 }) // ... } “Start”; “[127, 100, 114]”; “End”;
当你使用filter
时,希望筛选具有特定结果的数组。假设过滤数量大于20的数组。
如果你正常使用filter
(没有 await),如下:
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') }
运行结果
Start ["apple"] END
filter
中的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
为什么会发生这种情况?
当在filter
回调中使用await
时,回调总是一个promise
。由于promise
总是真的,数组中的所有项都通过filter
。在filter
使用 await
await
를 사용할 때 주목할 만한 몇 가지 문제를 공유합니다. 🎜const filtered = array.filter(true);
fruitBasket
에서 각 과일의 수량을 가져오려고 합니다. 과일 수를 얻으려면 getNumFruit
함수를 사용할 수 있습니다. 🎜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') }
fruitBasket
을 얻었다고 가정하고 여기서는 setTimeout
을 사용하여 시뮬레이션합니다. 🎜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') }
await
및 getNumFruit
를 사용하여 비동기 함수에서 각 과일의 수를 가져오고 싶다고 가정해 보겠습니다. 🎜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') }
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') }
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') }
for
루프에서 getNumFruit
를 사용하여 각 과일의 수를 가져와서 콘솔에 인쇄합니다. 🎜🎜 getNumFruit
는 promise
를 반환하므로 await
를 사용하여 결과가 반환될 때까지 기다렸다가 인쇄합니다. 🎜rrreee🎜 await
를 사용할 때 JavaScript가 Promise가 처리 결과를 반환할 때까지 실행을 일시 중지하려고 합니다. 이는 for
루프 내의 await
가 순차적으로 실행되어야 함을 의미합니다. 🎜🎜결과는 예상한 대로입니다. 🎜rrreee🎜🎜🎜 이 동작은 대부분의 루프(예: while
및 for-of
루프)에서 작동합니다...🎜🎜그러나 forEach와 같이 콜백이 필요한 루프는 처리할 수 없습니다.
코드>, 맵
, 필터
및 축소
. 다음 몇 섹션에서는 await
가 forEach
, map 및 filter
에 어떤 영향을 미치는지 살펴보겠습니다. 🎜forEach
를 사용하여 배열을 탐색합니다. 🎜rrreee🎜다음으로 getNumFruit
를 사용하여 과일 수를 가져오겠습니다. (콜백 함수의 async
키워드에 유의하세요. 콜백 함수에 await
가 있기 때문에 이 async
키워드가 필요합니다). 🎜rrreee🎜 콘솔이 다음을 인쇄할 것으로 예상했습니다. 🎜rrreee🎜 하지만 실제 결과는 다릅니다. forEach
루프에서 반환 결과를 기다리기 전에 JavaScript는 먼저 console.log('End')를 실행합니다. 🎜🎜실제 콘솔 인쇄는 다음과 같습니다. 🎜rrreee🎜🎜🎜 JavaScript의 forEach
는 약속 인식을 지원하지 않으며 async
및 await
도 지원하므로 이를 수행할 수 없습니다. forEach
에서 사용하려면 await
를 사용하세요. 🎜map
에서 await
을 사용하는 경우 > , map
은 항상 promise
배열을 반환합니다. 비동기 함수는 항상 promise
를 반환하기 때문입니다. 🎜rrreee🎜🎜🎜 map
에서 await
를 사용하면 map
은 항상 promise
를 반환하고 promise
를 기다려야 합니다. code> 배열이 처리됩니다. 또는 await Promise.all(arrayOfPromises)
를 통해 수행하세요. 🎜rrreee🎜실행 결과는 다음과 같습니다. 🎜🎜🎜🎜원하시면 promise
에서 반환 값을 처리할 수 있으며, 파싱된 값이 반환 값이 됩니다. 🎜rrreeefilter
를 사용할 때 필터가 특정 결과 배열이 있습니다. 숫자가 20보다 큰 배열을 필터링한다고 가정해 보겠습니다. 🎜🎜대기 없이 정상적으로 filter
를 사용하면 다음과 같이 됩니다. 🎜rrreee🎜Running results🎜rrreee🎜await
in filter
가 종료되지 않습니다. 동일한 방식으로 작동합니다. 실제로는 전혀 작동하지 않습니다. 🎜rrreee🎜🎜🎜 왜 이런 일이 발생하나요? 🎜🎜 filter
콜백 내에서 await
를 사용할 때 콜백은 항상 promise
입니다. promise
는 항상 true이므로 배열의 모든 항목은 filter
를 통과합니다. await
클래스🎜를 사용하여 filter
에서 다음 코드를 사용하세요.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
更多编程相关知识,请访问:编程学习网站!!
위 내용은 JavaScript 루프에서 async/await를 사용하는 방법은 무엇입니까? 무엇에 주의해야 합니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!