async/await在for...of、for或while循环中才能顺序执行;forEach、map等不识别async回调,导致并行执行。正确写法:async function runInSequence(items) { for (const item of items) { await fetchItem(item); } }
async/await 循环中 await 不生效?其实是没等对地方
直接在
循环里写
是能顺序执行的,但很多人误用
或
导致“看似写了 await,实际并行跑完”。根本原因是:这些数组方法不识别
回调,它们只把返回的
当普通值扔进数组,不等 resolve 就继续下一轮。
正确做法是用标准
、
或
循环 —— 它们天然支持
暂停。
里写
→ 所有调用立刻发起,并行执行,循环不等待
+
→ 并行执行,不是“依次”
中
→ 真正逐个等待,顺序执行
for...of 是最直观且兼容性最好的选择
它语义清晰、调试友好、所有现代环境(包括 Node.js 14+ 和主流浏览器)都支持。注意变量作用域和异步函数声明位置:
不要把
声明写在循环体内(比如
),那只是定义函数,没调用
如果需要带索引,用
带来额外 Promise 包装
若循环体逻辑复杂,可抽成独立
函数,但调用时仍要
错误处理必须包裹在循环内部
顺序执行时,一个失败默认会中断整个流程。是否继续取决于业务逻辑 —— 但不管怎样,不能让未捕获的
导致进程退出或静默失败。
用
包住单次
,出错可记录、跳过或重试
避免把整个
块包进一个
:那样一旦出错就终止后续所有任务,且无法区分哪次失败
如果某次请求失败后还想继续,写成:
性能敏感场景下需警惕“纯串行”的代价
顺序执行本质是零并发,吞吐量低。比如 10 个 200ms 的 API 请求,串行要 2s;并行只要 ~200ms。所以得先确认“必须依次”是不是真需求:
依赖前序结果(如 token 刷新后才能发下一请求)→ 必须串行
只是怕压垮服务端 → 可改用
分批控制并发数(例如每次最多 3 个)
前端轮询状态,需严格按时间先后 → 串行合理;但可考虑用
+ 递归代替循环,更易中断
真正容易被忽略的是:很多人在调试时用
看执行顺序,却忘了
本身非原子操作,尤其在 Node.js 中可能因缓冲导致日志错乱 —— 验证是否真顺序,优先看网络面板或加
打点。
forawait someAsyncFn()forEachmapasyncPromisefor...offorwhileawaitforEachasync (item) => { await fn(item) }mapawait Promise.all(...)for...ofawait fn(item)async function runInSequence(items) {
for (const item of items) {
const result = await fetchItem(item); // 每次等完才进下一轮
console.log(result);
}
}asyncfor (...) { async () => { ... } }for (let i = 0; i 更稳妥,避免 entries()asyncawaitPromise rejectiontry/catchawaitfortry/catchtry { await fn(item) } catch (e) { console.error('failed on', item, e) }Promise.allSettledsetTimeoutconsole.logconsole.logDate.now()