关键在于是否等待前一个异步完成:要保序用for...of+await;求快且保序用Promise.all+map;需控并发又保序用async-pool或手写节流;避免forEach+async、for...in及漏await等常见错误。

关键不在“怎么遍历”,而在于“要不要等前一个完成再开始下一个”——这直接决定用串行还是并行,也决定了结果顺序是否可控。
要严格保序:用 for...of + await
适合打印报表、依赖上一步结果、防接口限流等场景。每次循环都会暂停,等当前异步操作 resolve 后才进下一轮。
- 写法清晰,逻辑直白,不易出错
- 错误不会中断整个流程,可单独捕获并处理(如记录日志、填 null、跳过)
- 别用 forEach + async:它不等待 Promise,所有请求会瞬间发出,顺序完全不可控
要最快完成且结果保序:用 Promise.all + map
适合多个独立请求(比如批量查用户信息),后端能扛并发,且你只要最终结果按原数组顺序排列。
- 所有请求同时发起,响应快的先回来,但 Promise.all 会按原始索引归位结果
- 任一失败则整体 reject,需配合 .catch() 或 try/catch 处理容错
- 若想失败不影响其他,可用 Promise.allSettled 替代
要控并发数又保序:用 async-pool 或手写节流
当数组很长(比如几百个请求),全量并发可能压垮服务端或触发限流,但串行又太慢。
- async-pool 可设最大并发数(如 limit: 5),内部自动调度,结果仍按原顺序返回
- 手写方案可用 reduce 累积 Promise 链,或维护运行中任务队列 + 递归触发
- 比 Promise.all 更稳,比 for...of 更快,是折中首选
容易踩的坑
除了 forEach + async 这个经典雷区,还要注意:
- for...in 遍历数组不推荐——它遍历的是属性名(包括原型链),顺序也不保证
- Promise.all 的入参必须是 Promise 实例数组;map 中漏写 await 会导致传入函数而非 Promise
- 没加 try/catch 或 .catch(),未处理的 rejected Promise 会让整个流程静默失败











