彻底搞懂Promise.allSettled:用法、场景、源码手写、面试题详解

前言

在前端异步开发中,Promise.all 是我们最常用的并发解决方案,但它存在致命短板:一个失败,全部失败

实际业务中,很多场景下我们允许部分接口/任务失败,只需要等待所有任务执行完毕,统一收集成功和失败的结果,这就是 Promise.allSettled 的核心价值。

本文将从零讲解 Promise.allSettled,包含基础语法、实战案例、与其他 Promise 方法对比、手写源码、高频面试题,全程干货,可直接收藏学习、发布使用。


一、核心概念

1. 定义

Promise.allSettled() 是 ES2020 新增的 Promise 静态方法,用于并行执行多个 Promise 任务,等待所有任务全部执行完毕(无论成功/失败)后,统一返回所有任务的执行结果。

2. 核心特性

  • 永不短路:不会因为某个 Promise 失败而终止执行
  • 永不 reject:最终返回的 Promise 永远是 fulfilled 状态
  • 全量收集:统一收集每一个任务的成功结果或失败原因

3. 语法格式

javascript 复制代码
Promise.allSettled(iterable)
  • 入参:可迭代对象(通常是 Promise 数组)
  • 返回值:状态为 fulfilled 的 Promise,结果为结果对象数组

二、返回值结构详解

allSettled 返回的结果数组中,每一项都是固定格式的对象,分为成功和失败两种形态:

1. 任务成功(fulfilled)

javascript 复制代码
{
  status: 'fulfilled', // 固定标识:成功
  value: 成功的结果数据  // 任务返回值
}

2. 任务失败(rejected)

javascript 复制代码
{
  status: 'rejected',  // 固定标识:失败
  reason: 失败的错误信息 // 错误原因/异常对象
}

三、基础实战案例

我们创建 3 个 Promise 任务(包含成功、失败场景),直观感受执行效果:

javascript 复制代码
// 构造多个异步任务
const p1 = Promise.resolve("接口1请求成功");
const p2 = Promise.reject(new Error("接口2请求失败"));
const p3 = Promise.resolve("接口3请求成功");

// 执行allSettled
Promise.allSettled([p1, p2, p3]).then((res) => {
  console.log("所有任务执行完毕:", res);
});

输出结果:

javascript 复制代码
[
  { status: 'fulfilled', value: '接口1请求成功' },
  { status: 'rejected', reason: Error: 接口2请求失败 },
  { status: 'fulfilled', value: '接口3请求成功' }
]

可以看到:即使有任务失败,所有结果依然全部返回。


四、业务实用写法(筛选成功/失败数据)

实际开发中,我们需要单独筛选出成功的有效数据和失败的异常任务,封装通用处理逻辑:

javascript 复制代码
async function batchRequest() {
  const p1 = Promise.resolve({ id: 1, name: "数据1" });
  const p2 = Promise.reject(new Error("数据2加载失败"));
  const p3 = Promise.resolve({ id: 3, name: "数据3" });

  // 等待所有任务完成
  const resultList = await Promise.allSettled([p1, p2, p3]);

  // 筛选成功的结果
  const successData = resultList
    .filter((item) => item.status === "fulfilled")
    .map((item) => item.value);

  // 筛选失败的任务
  const errorData = resultList
    .filter((item) => item.status === "rejected")
    .map((item) => item.reason.message);

  console.log("成功数据:", successData);
  console.log("失败原因:", errorData);
}

batchRequest();

输出结果:

javascript 复制代码
成功数据: [ { id: 1, name: '数据1' }, { id: 3, name: '数据3' } ]
失败原因: [ '数据2加载失败' ]

五、核心使用场景

Promise.allSettled 专门适配多任务并行、允许部分失败、需要全量结果统计的场景:

  1. 批量接口请求:页面初始化同时请求多个无关接口,个别接口失败不影响整体页面渲染
  2. 批量上传文件:多文件并行上传,统计哪些上传成功、哪些上传失败,支持重试
  3. 批量数据校验/提交:批量提交表单、批量处理数据,全部执行完毕后统一提示结果
  4. 数据埋点上报:多组埋点并行上报,无需因为单个上报失败中断整体逻辑

六、Promise 四大并发方法对比(重点面试考点)

很多面试会考察 all / allSettled / race / any 的区别,一张表彻底分清:

方法 执行特性 结束条件 适用场景
Promise.all 短路失败 全部成功才成功,一个失败直接失败 多个接口强依赖,必须全部成功
Promise.allSettled 无短路 所有任务执行完毕,永不 reject 批量任务,允许部分失败,需统计全量结果
Promise.race 竞速执行 谁先完成(成功/失败)就返回谁 接口超时拦截、竞速请求
Promise.any 容错成功 一个成功就成功,全部失败才失败 多备用接口请求,只要一个成功即可

七、手写 Promise.allSettled(面试必刷源码)

面试高频手写题,实现核心逻辑:遍历所有 Promise、捕获成功/失败、全部完成后统一返回结果。

javascript 复制代码
/**
 * 手写 Promise.allSettled
 * @param {Array} promiseArr Promise数组
 * @returns {Promise} 包含所有任务结果的Promise
 */
function myAllSettled(promiseArr) {
  // 返回一个新Promise
  return new Promise((resolve) => {
    const result = []; // 存储所有任务结果
    let finishCount = 0; // 记录完成的任务数
    const len = promiseArr.length;

    // 兼容空数组情况
    if (len === 0) {
      resolve([]);
      return;
    }

    // 遍历执行所有Promise
    for (let i = 0; i < len; i++) {
      // 统一转为Promise对象(兼容普通值)
      Promise.resolve(promiseArr[i])
        .then((value) => {
          // 成功:存入fulfilled状态结果
          result[i] = { status: "fulfilled", value };
        })
        .catch((reason) => {
          // 失败:存入rejected状态结果
          result[i] = { status: "rejected", reason };
        })
        .finally(() => {
          // 每完成一个任务,计数+1
          finishCount++;
          // 所有任务执行完毕,返回结果
          if (finishCount === len) {
            resolve(result);
          }
        });
    }
  });
}

// 测试手写方法
const p1 = Promise.resolve("成功1");
const p2 = Promise.reject("失败2");
myAllSettled([p1, p2]).then(res => console.log(res));

源码核心思路:

  1. 遍历传入的所有异步任务,兼容普通值和 Promise 对象
  2. 每个任务单独捕获成功/失败,标记对应状态
  3. 通过计数器统计完成数量,全部完成后统一 resolve 结果
  4. 永远不会触发 reject,贴合原生 API 特性

八、高频面试问答题

1. 说一下 all 和 allSettled 的区别?

  1. Promise.all 有短路机制,一个任务失败,整体直接 reject,无法获取剩余任务结果;
  2. Promise.allSettled 无短路,会等待所有任务执行完毕,统一收集成功、失败结果,返回的 Promise 永远为成功状态;
  3. all 适用于任务强依赖场景,allSettled 适用于批量容错场景。

2. allSettled 为什么不需要 catch 捕获?

因为 allSettled 本身设计为永不 reject,无论内部任务是否失败,最终返回的 Promise 一定是 fulfilled 状态,因此无需通过 catch 捕获异常。


九、总结

  1. Promise.allSettled 核心:全量执行、全量收集、永不报错
  2. 业务核心用途:批量异步任务、允许部分失败、需要统计执行结果
  3. 面试重点:与 all/race/any 的区别、手写源码、应用场景辨析

💡 建议收藏 :开发中遇到批量并行异步任务,优先考虑使用 allSettled 替代 all,容错性更强!

相关推荐
心易行者1 小时前
Python在线运行+SQLite数据库实战:0成本搭个人数据后台,5个场景直接套用
前端·网络·人工智能·python
@tangguo1232 小时前
npm 和 yarn 配置说明
前端·javascript·npm·node.js·yarn
zhiyouTech2 小时前
GEO实战:把生成式引擎优化当成检索工程来做(含五断点诊断与50题Benchmark)
前端·人工智能
志尊宝2 小时前
Vue3 零基础每日笔记(052):路由常见坑一次排雷——404、刷新丢参数、部署白屏
前端·javascript·vue.js·笔记·html5
linux_cfan2 小时前
videojs v10 源代码系列解读:13 · 能力型媒体契约:`Media` 的组合接口
前端·javascript·音视频
涛涛ing2 小时前
2026年9月,前端圈同时发生了四件事,指向同一个方向
前端
艾伦野鸽ggg2 小时前
Vue2 模板语法与样式绑定
前端
Amos_Web2 小时前
Rspack 源码解析(十一):资产 Hook 与增量构建
前端·rust·源码阅读
PC2005_cloud2 小时前
Windows 数据使用量页面卡死:1097 个热点档案和 161 MB 的 SRUM 库
前端·后端