异步循环需用for...of或for循环配合await实现顺序执行,禁用foreach/map/filter等无法阻塞的数组方法;每个await须配独立try/catch容错;串行适用于依赖场景,并行+限流更高效。

想让异步操作在循环中按顺序一个接一个执行,关键不是“能不能用 await”,而是“在哪用、怎么包、怎么容错”。核心原则就一条:必须用支持 await 的循环结构,且 await 要落在可暂停的执行流里。
优先用 for...of 或传统 for 循环
它们是天然支持 await 的结构,每次迭代都会等待上一次异步完成后再进入下一轮。
- 写法简洁清晰:
for (const item of items) { await doAsync(item); } - 能自然拿到当前值,不需要额外索引变量
- 若需索引,用
for (let i = 0; i 更稳妥,避免 <code>entries()引入多余 Promise 包装 - 逻辑复杂时,可把异步体抽成独立 async 函数,但调用时仍要
await
别在 forEach、map、filter 里直接 await
这些数组方法的回调函数本身不是 async 上下文,就算加了 async,也只是定义了个异步函数,不会阻塞循环本身。
-
arr.forEach(async item => { await fn(item); })→ 所有请求并发发出,不保证顺序,且后续代码立刻执行 -
arr.map(async item => await fn(item))→ 返回的是 Promise 数组,不是结果数组;想取结果得再套Promise.all() -
arr.filter(async item => await check(item))→ 因为 async 函数总返回真值 Promise,过滤会失效
错误处理必须落在单次 await 外围
顺序执行时,一次失败默认中断整个流程。是否继续,取决于业务,但绝不能让错误静默抛出。
- 每个 await 都该配独立 try/catch:
try { await fetch(item) } catch (e) { console.error('失败于', item, e) } - 不要把整个 for 块包进一个 try/catch:那样一出错就停掉所有后续任务,也无法定位具体哪次失败
- 想跳过失败项继续执行,就在 catch 里处理(记录、重试或忽略)即可
确认你真的需要“顺序执行”
串行虽简单,但性能代价明显。10 个 200ms 请求,串行耗时约 2 秒,并行只要约 200ms。
- 必须串行的典型场景:后一步依赖前一步结果(如刷新 token 后再发请求)
- 只是怕压垮服务端?可改用
Promise.allSettled并发 + 限流控制 - 想兼顾速度与可控性,可用
Promise.all并行发起,再按需排序或组装结果
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











