标准答案

  1. Promise.all:等待所有 Promise fulfilled 后才成功,结果按传入顺序组成数组;只要有一个 rejected 就整体 rejected。适合多个任务都必须成功的场景。
  2. Promise.allSettled:等待所有任务 settled,不管成功失败,返回每个任务的状态和值或原因。适合批量请求后做汇总展示,不能因为一个失败影响其它结果。
  3. Promise.race:谁先 settled 就采用谁的结果,不管成功还是失败。常用于超时控制、最快响应优先,但要注意未胜出的任务不会自动取消。
  4. Promise.any:谁先 fulfilled 就成功,只有全部 rejected 才失败并抛 AggregateError。适合多个备选源只要一个成功即可的场景。并发数量控制不是这些 API 自动提供的,需要额外写任务调度。

题目解析

Promise 组合方法的区别不在“能不能并发”,而在“什么时候成功、什么时候失败、返回什么结构”。任务是否并发,取决于 Promise 是否已经被创建和启动,不是 Promise.all 自己把任务变并发。

Promise.all 适合强依赖场景:任意一个失败,整体就不能继续。allSettled 适合弱依赖场景:每个结果都要展示或统计,失败也要被记录下来。

race 和 any 最容易混。race 看最先 settled 的结果,成功失败都算;any 只看最先 fulfilled 的结果,只有全部失败才失败。这个差异决定了 race 更适合超时控制,any 更适合多源兜底。

这些 API 都不负责取消未完成任务,也不负责限制并发数量。要做超时取消需要 AbortController,要做并发控制需要任务队列或调度器。

代码示例

下面例子能把 Promise 组合方法的失败行为区分开。

JavaScript
const tasks = urls.map(url => fetch(url))

// 全部成功才继续
const responses = await Promise.all(tasks)

// 不管成功失败都收集结果
const results = await Promise.allSettled(tasks)

// 超时控制:谁先 settled 用谁
const withTimeout = Promise.race([
  fetch('/api/data'),
  new Promise((_, reject) => {
    setTimeout(() => reject(new Error('timeout')), 3000)
  })
])

// 多个镜像源,只要一个成功
const fastestOk = await Promise.any([
  fetch('/mirror-a'),
  fetch('/mirror-b')
])

常见误区

  • 误以为 Promise.all 会顺序执行任务。任务是否并发取决于 Promise 何时被创建。
  • 误以为 allSettled 会因为某个任务失败而 reject。
  • 混淆 race 和 any:race 看最先 settled,any 看最先 fulfilled。

作者信息