Forest树洞

对比 Promise.all() 和 Promise.allSettled()

2025/11/03
1
0

📜 Promise 并发控制:all()allSettled() 深度解析

在 JavaScript 异步编程中,处理多个 Promise 是常见的需求。Promise 对象提供了几个强大的静态方法来管理这些并发任务,其中最常用的是 Promise.all()Promise.allSettled()

虽然它们都用于等待一组 Promise 完成,但在错误处理机制和返回值结构上存在根本差异,适用于不同的业务场景。

1. ⚔️ Promise.all():全有或全无(Fail-fast)

Promise.all() 是最经典的并发控制方法,它要求所有传入的 Promise 必须成功(resolve)才能成功。

核心特性

特性说明
错误处理快速失败 (Fail-fast):只要输入数组中有一个 Promise 被拒绝(reject),Promise.all() 就会立即返回一个被拒绝的 Promise,并携带第一个拒绝的原因。它不会等待其余未完成的 Promise。
返回值如果全部成功,返回一个 Promise,该 Promise 解决为一个值的数组,数组顺序与输入 Promise 的顺序一致。
适用场景任务之间存在强依赖关系,任何一个任务的失败都将导致整个后续操作无法进行。

示例

// 假设 fnA 成功,fnB 失败
const promiseA = Promise.resolve('数据 A');
const promiseB = Promise.reject(new Error('B 任务失败')); 
const promiseC = new Promise(res => setTimeout(() => res('数据 C'), 5000)); // 耗时任务

async function usePromiseAll() {
  try {
    // promiseB 立即失败,Promise.all 会立刻拒绝,promiseC 不会被等待。
    const results = await Promise.all([promiseA, promiseB, promiseC]);
    console.log('成功结果:', results); // 不会执行
  } catch (error) {
    console.error('错误原因:', error.message); 
    // 输出: "错误原因: B 任务失败"
  }
}

// usePromiseAll();

2. 🛡️ Promise.allSettled():坚如磐石(Wait-for-all)

Promise.allSettled() 是 ES2020 引入的方法,它设计的初衷是为了确保无论 Promise 成功或失败,都能获取所有任务的结果。

核心特性

特性说明
错误处理永不失败:它总是等待所有传入的 Promise 都达到“敲定”(Settled)状态,即全部完成(无论是 fulfilled 还是 rejected)。它返回的 Promise 永远会成功解决
返回值返回一个 Promise,该 Promise 解决为一个结果对象的数组,数组中每个对象描述了对应 Promise 的最终状态和值/原因。
适用场景任务之间互相独立,需要确保所有任务都执行完毕,并且需要获取每个任务的具体成功或失败信息。

示例

// 假设 fnA 成功,fnB 失败
const promiseA = Promise.resolve('数据 A');
const promiseB = Promise.reject(new Error('B 任务失败'));
const promiseC = new Promise(res => setTimeout(() => res('数据 C'), 5000));

async function usePromiseAllSettled() {
  // 即使 promiseB 失败,await 也会等待 promiseA, B, C 全部完成
  const results = await Promise.allSettled([promiseA, promiseB, promiseC]);
  
  console.log('全部结果:', results); 
  /* 输出: 
  [
    { status: 'fulfilled', value: '数据 A' },
    { status: 'rejected', reason: [Error: B 任务失败] },
    { status: 'fulfilled', value: '数据 C' }
  ]
  */

  // 优雅地处理结果
  const successfulResults = results
    .filter(p => p.status === 'fulfilled')
    .map(p => p.value);
    
  console.log('成功的数据:', successfulResults);
}

// usePromiseAllSettled();

3. ⚖️ 关键对比总结

特性Promise.all()Promise.allSettled()
是否会失败是(只要有一个 Promise 拒绝,它就会失败)否(永远成功解决)
等待机制快速失败,不等待失败后的 Promise等待所有 Promise 完成(成功或失败)
返回值结构纯粹的值数组 [value1, value2, ...]状态对象数组 [{status: 'fulfilled', value: ...}, {status: 'rejected', reason: ...}]
适用场景必须全部成功(例如:加载多个依赖配置文件)需要获取所有任务结果,并容忍部分失败(例如:发送多条不相关日志/通知)

💡 结论

在选择使用哪个方法时,请问自己:“如果这些并发任务中有一个失败了,我的程序还能继续进行吗?”

  • 如果不能,并且需要立即停止并处理错误,请使用 Promise.all()
  • 如果可以,并且你需要知道每个任务的最终状态,请使用 Promise.allSettled()