如何在JavaScript循环中使用异步/等待

如何在JavaScript中按顺序或并行运行异步循环?


在进行异步魔术之前,我想提醒您经典同步循环是什么样的。


同步循环


很久以前,我以这种方式编写了循环(也许您也是如此):


for (var i=0; i < array.length; i++) { var item = array[i]; //  -  item } 

这个周期既好又快。 但是他在可读性和支持方面存在很多问题。 一段时间后,我习惯了最佳版本:


 array.forEach((item) => { //  -  item }); 

JavaScript发展很快。 出现新功能和语法。 我最喜欢的增强功能之一是async / await


现在,我经常使用这种语法。 有时在某些情况下,我需要异步处理数组元素。


异步循环


如何在循环体内使用await ? 让我们尝试编写一个异步函数,并期待处理每个元素的任务:


 async function processArray(array) { array.forEach(item => { //       //     ! await func(item); }) } 

此代码将引发错误。 怎么了 因为我们不能在同步函数中使用await 。 如您所见, processArray是一个异步函数。 但是我们为forEach使用的匿名函数是同步的


该怎么办?


1.不要等待执行结果


我们可以将匿名函数定义为异步的:


 async function processArray(array) { array.forEach(async (item) => { await func(item); }) console.log('Done!'); } 

但是forEach不会等待任务完成。 forEach是一个同步操作。 她将只是启动任务并继续前进。 让我们检查一个简单的测试:


 function delay() { return new Promise(resolve => setTimeout(resolve, 300)); } async function delayedLog(item) { //    await  Promise //    delay await delay(); console.log(item); } async function processArray(array) { array.forEach(async (item) => { await delayedLog(item); }) console.log('Done!'); } processArray([1, 2, 3]); 

在控制台中,我们将看到:


 Done! 1 2 3 

在某些情况下,这可能是正常结果。 但是,在大多数情况下,这不是合适的逻辑。


2.按顺序处理循环


为了等待循环体执行的结果,我们需要返回到旧的“ for”循环。 但是这次,我们将使用其新版本与for..of构造(感谢迭代协议 ):


 async function processArray(array) { for (const item of array) { await delayedLog(item); } console.log('Done!'); } 

这将给我们预期的结果:


 1 2 3 Done! 

数组的每个元素将被顺序处理。 但是我们可以并行运行循环!


3.并行处理循环


您需要稍微修改代码以并行开始操作:


 async function processArray(array) { //  "map"    const promises = array.map(delayedLog); //       await Promise.all(promises); console.log('Done!'); } 

此代码可以并行运行多个delayLog任务。 但是要小心使用大型阵列。 对于CPU和内存来说,太多任务可能太难了。


另外,请不要将示例中的“并行任务”与真正的并行性和线程混淆。 此代码不保证并行执行。 一切都取决于循环的主体(在示例中,它是delayedLog )。 网络请求,网络工作者和其他一些任务可以并行执行。

Source: https://habr.com/ru/post/zh-CN435084/


All Articles