不要用forEach执行异步任务

forEach无法保证执行顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
async function processRoles() {
let roles = ['admin', 'editor', 'employee'];
roles.forEach(async role => {
const result = await performTask(role);
console.log(result);
});
console.log('任务处理完成');
}

function performTask(role) {
return new Promise((resolve, reject) => {
// 模拟异步操作
setTimeout(() => {
resolve(`已处理角色:${role}`);
}, Math.random() * 1000);
});
}

processRoles();

如果业务场景要求保证执行顺序,则需要输出为:

1
2
3
4
已处理角色:admin
已处理角色:editor
已处理角色:employee
任务处理完成

但 forEach 实际输出可能乱序:

1
2
3
4
任务处理完成
已处理角色:employee
已处理角色:admin
已处理角色:editor

forEach逻辑

1
2
3
4
5
6
for (var i = 0; i < length; i++) {
if (i in array) {
var element = array[i];
callback(element, i, array);
}
}

for…of保证执行顺序

1
2
3
4
5
6
7
8
async function processRoles() {
let roles = ['admin', 'editor', 'employee'];
for (const role of roles) {
const result = await performTask(role);
console.log(result);
}
console.log('任务处理完成');
}

for…of逻辑

for…of 的实现是基于迭代器的

1
2
3
4
5
6
7
8
9
10
11
12
13
async function processRoles() {
let roles = ['admin', 'editor', 'employee'];
let iterator = roles[Symbol.iterator]();
let res = iterator.next();
while(!res.done) {
let value = res.value;
console.log(value);
console.log(await performTask(value));
res = iterator.next();
}
console.log('任务处理完成');
}
processRoles()

用栈来理解

foreach里参数是fn。每一次循环都是一个新的栈。所以await不起作用,因为栈内本来也就一个函数。

for/for…of的循环都在同一个栈内。需要等一个实现完才到下一个。

参考

https://juejin.cn/post/7236313127070105637


不要用forEach执行异步任务
http://example.com/2023/06/04/不要用forEach执行异步任务/
Author
John Doe
Posted on
June 4, 2023
Licensed under