1.for中使用
const skills = ["js", "vue", "node", "react"];
function getSkillPromise(value) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(value);
}, 1000);
});
}
async function test() {
for (let i = 0; i < skills.length; i++) {
const skill = skills[i];
const res = await getSkillPromise(skill);
console.log(res);
}
}
test(); // 调用
当使用await时,希望JavaScript暂停执行,直到等待 promise 返回处理结果。上述结果意味着for循环中有异步代码,是可以等到for循环中异步代码完全跑完之后再执行for循环后面的代码。
但是他不能处理回调的循环,如forEach、map、filter等,下面具体分析。
2.map中使用
在map中使用await, map 的返回值始是promise数组,这是因为异步函数总是返回promise。
async function test() {
console.log("start");
const res = skills.map(async item => {
return await getSkillPromise(item);
});
console.log(res);
console.log("end");
}
test();
结果:始终为promise数组
start
[
Promise { <pending> },
Promise { <pending> },
Promise { <pending> },
Promise { <pending> }
]
end
若果你想要等到promise的返回结果,可以使用promise.all()处理一下
async function test() {
console.log("start");
const res = skills.map(async item => {
return await getSkillPromise(item);
});
const resPromise = await Promise.all(res);
console.log(resPromise);
console.log("end");
}
test();
// 结果
start[("js", "vue", "node", "react")];
end;
3.forEach中使用
先上代码
async function test() {
console.log("start");
skills.forEach(async item => {
const res = await getSkillPromise(item);
console.log(res);
});
console.log("end");
}
test();
预期结果
"Start";
"js";
"vue";
"node";
"react";
"End";
实际结果 在forEach循环等待异步结果返回之前就执行了console.log(‘end’)
"Start";
"End";
"js";
"vue";
"node";
"react";
JavaScript 中的 forEach不支持 promise 感知,也不支持 async 和await,所以不能在 forEach 使用 await 。
4.filter中使用
正常使用 filter:
async function test() {
console.log("start");
const res = skills.filter(item => {
return ["vue", "react"].includes(item);
});
console.log(res);
console.log("end");
}
test(); // 调用
// 结果
start[("vue", "react")];
end;
使用 await后:
async function test() {
console.log("start");
const res = skills.filter(async item => {
const skill = await getSkillPromise(item);
return ["vue", "react"].includes(item);
});
console.log(res);
console.log("end");
}
test();
预期结果:
start[("vue", "react")];
end;
实际结果:
start[("js", "vue", "node", "react")];
end;
结论:因为异步函数getSkillPromise返回结果返回的promise总是真的,所以所有选项都通过了过滤
5.for…of 中使用(推荐)
for...of 和 for 一样能正确 await,且写法更简洁,是现在的首选:
async function test() {
for (const skill of skills) {
const res = await getSkillPromise(skill);
console.log(res); // 逐个、按顺序输出
}
}
串行还是并发?
上面 for / for...of 是串行(一个完了才下一个,总耗时 ≈ 每个之和)。如果各任务之间没有依赖、想并发提速,用 map + Promise.all:
// 并发:四个请求同时发出,总耗时 ≈ 最慢的那个
const res = await Promise.all(skills.map(item => getSkillPromise(item)));
console.log(res); // ["js","vue","node","react"] 顺序与 skills 一致
怎么选:
- 任务有先后依赖(后一个要用前一个的结果)→ 用
for/for...of串行。 - 任务互相独立、且数量不大 → 用
map+Promise.all并发,更快。 - 任务数量很大(如上千条)→ 别一次性
Promise.all打爆,做分批或并发限制。
小结
- 想顺序执行
await:用for或for...of(推荐)。 - 永远别在
forEach里用await——它不感知 Promise,会直接跳过。 filter/reduce里也别用await;真要”先异步再过滤”,先用map拿全量结果,再filter和reduce。