当我们使用 async/await
来处理异步函数时,有可能会遇到在 forEach
循环中使用 await
语句,导致 await
处理不完整的问题,这是因为 forEach
循环的特殊性导致的。
问题
forEach
循环是 JavaScript 提供的一种遍历数组的方式,常用于对数组中的每一项进行操作,语法如下:
array.forEach(callback(currentValue [, index [, array]]) {
// 处理逻辑
}[, thisArg]);
其中 callback
是一个函数,用于处理数组中的每一项,currentValue
是数组中的当前项,index
是当前项的索引位置,array
是数组本身,thisArg
是执行 callback
时的 this
值,默认是 undefined
。
在 forEach
中使用 await
的问题就在于,await
只会等待 Promise
对象完成,然而 forEach
并不会等待回调函数完成,而是在每次调用回调函数之后立即执行下一轮循环,导致 await
处理不完整。
以下是一个示例:
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
const array = [1, 2, 3];
array.forEach(async item => {
await delay(1000);
console.log(item);
});
console.log('done');
在这个示例中,我们使用了 delay
函数来延迟 1 秒钟,然后在 forEach
循环中使用 await
来等待这个延迟。但是,我们会发现 done
被先输出了,然后才是数组中的每一项,这是因为 forEach
循环不会等待回调函数的完成。
解决方案
解决这个问题的方法之一是使用 for...of
循环,因为 for...of
会等待每一个循环体内的异步操作完成,而不是像 forEach
那样不等待直接执行下一次循环。
以下是一个 for...of
的示例:
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
const array = [1, 2, 3];
for (const item of array) {
await delay(1000);
console.log(item);
}
console.log('done');
在这个示例中,我们使用了 for...of
循环,将数组中的每一项作为变量 item
,然后使用 await
语句等待 delay
函数的延迟完成。这个示例会正确输出数组中的每一项,然后输出 done
,说明 for...of
循环可以正确地等待异步操作完成。
另外一种解决方案是使用 Promise.all
来并行执行异步任务,然后使用 map
方法将每个任务映射为一个 Promise 对象,代码如下:
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
const array = [1, 2, 3];
await Promise.all(array.map(async item => {
await delay(1000);
console.log(item);
}));
console.log('done');
在这个示例中,我们使用 Promise.all
来并行执行异步任务,然后使用 map
方法将每个任务映射为一个 Promise 对象,然后使用 await
语句等待所有 Promise 对象的完成。这个示例也会正确输出数组中的每一项,然后输出 done
。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:重学 JS:为啥 await 不能用在 forEach 中详解 - Python技术站