数组遍历
forEach
函数与 map
相似,但是它不返回结果,而是为每个元素运行该函数并丢弃结果。 实际上,重要的部分是调用函数的副作用。
例如,将每个元素同步打印到控制台
const arr = [1, 2, 3];
arr.forEach((i) => {
console.log(i);
});
// 1
// 2
// 3
console.log("完成同步");
// 完成同步
由于结果并不重要,因此可以使用异步函数作为迭代器:
const arr = [1, 2, 3];
arr.forEach(async (i) => {
// 每个元素需要花费不同的时间才能完成
await sleep(10 - i);
console.log(i);
});
console.log("完成异步");
// 完成异步
// 3
// 2
// 1
控制时间-等待完成
但是,并不奇怪,该函数被异步调用,并且程序没有按时间顺序完成。 这是与同步版本的重要区别,因为在执行下一行时,同步forEach已完成,而异步版本尚未完成。 因此,“完成异步”日志显示在元素之前。
要在继续进行之前等待所有函数调用完成,请使用带有 Promise.all
的 map
并不要返回值:
const arr = [1, 2, 3];
await Promise.all(arr.map(async (i) => {
await sleep(10 - i);
console.log(i);
}));
// 3
// 2
// 1
console.log("完成异步");
// 完成异步
进行此更改后,“完成异步”排在最后。
控制顺序-逐步完成
但是请注意,迭代函数是并行调用的。
若要忠实地遵循同步遍历,可以在reduce
中await
累加器,即如下的await memo
:
const arr = [1, 2, 3];
await arr.reduce(async (memo, i) => {
await memo;
await sleep(10 - i);
console.log(i);
}, undefined);
// 1
// 2
// 3
console.log("完成异步");
// 完成异步
这样,元素会依次处理,程序执行将等待整个数组完成后再继续。
结论
异步的数组遍历很容易使用,但是是用 forEach
,map
或 reduce
取决于时序要求。
- 如果你只想在任何时候运行这些功能,请使用
forEach
。 - 如果要确保继续操作之前完成操作,请使用
map
。 - 如果你需要一个一个地运行它们,请使用
reduce
。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。