前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库Promise.allSettled 结果结构
JavaScript异步与 Promise

Promise.allSettled 返回的数组里,每一项长什么样?

每一项都是一个对象,只有两种形状。成功的是 { status: 'fulfilled', value },失败的是 { status: 'rejected', reason }。数组顺序和传入顺序一致,判断成败要看 status 字段。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#异步与 Promise#异步编程
先看核心答案读代码示例
理解线索

两种形状,一个判别字段

  1. fulfilled成功项,兑现值放在 value 字段里
  2. rejected失败项,拒绝原因放在 reason 字段里
  3. status唯一可靠的判别字段,只有这两个取值

Promise.allSettled 返回的 Promise 本身永远不会 reject,所以在它后面写 catch 接不到任何一项的失败,失败信息全在结果数组里。

核心回答

先记住这个答案

Promise.allSettled 等所有任务都落定后,返回一个和输入等长的数组,每一项是一个描述结果的对象。成功的项长这样:{ status: 'fulfilled', value: 兑现值 };失败的项长这样:{ status: 'rejected', reason: 拒绝原因 }。一项只会有 value 或 reason 其中一个字段,顺序和传入顺序一致。它返回的 Promise 自己永远不会 reject。

  • 成功项是 status 加 value 两个字段
  • 失败项是 status 加 reason 两个字段
  • 结果顺序等于传入顺序,与完成先后无关
  • 判断成败只看 status,别看 value 有没有值

把四种输入的结果打印出来

成功的 Promise、失败的 Promise、普通值,再加一个不带原因的拒绝,看看每一项变成什么样。

逐项看字段JavaScript
Promise.allSettled([
  Promise.resolve(1),
  Promise.reject(new Error('超时')),
  'plain', // 普通值也会被当成成功
  Promise.reject() // 拒绝原因是 undefined
]).then((results) => {
  results.forEach((r) => console.log(Object.keys(r).join(' + '), '->', r.status))
  console.log(results[0].value, results[1].reason.message, results[2].value)
  console.log('reason' in results[3], results[3].reason)
})
查看输出与解释
status + value -> fulfilled
status + reason -> rejected
status + value -> fulfilled
status + reason -> rejected
1 超时 plain
true undefined

每一项都只有两个字段,没有第三种形状。普通值 'plain' 会先被 Promise.resolve 包一层,所以也算成功。 最后一项值得多看一眼:Promise.reject() 没给原因,结果对象里 reason 字段依然存在,只是值为 undefined。同理,一个兑现值是 undefined 的成功项,value 也是 undefined。所以用 r.value 有没有值来判断成败是靠不住的,唯一可靠的是 status。

拿到结果后怎么用

最常见的用法是把成功和失败拆开:成功的拿去渲染,失败的拿去上报或提示。

TypeScript 里用类型守卫收窄TypeScript
const results = await Promise.allSettled(ids.map((id) => getUser(id)))

// 类型守卫:告诉 TS 过滤后剩下的都是成功项
const users = results
  .filter((r): r is PromiseFulfilledResult<User> => r.status === 'fulfilled')
  .map((r) => r.value) // 这里 r.value 的类型是 User

const errors = results
  .filter((r): r is PromiseRejectedResult => r.status === 'rejected')
  .map((r) => r.reason) // reason 的类型是 any,用之前要自己判断

TypeScript 内置了这两种结果的类型:PromiseFulfilledResult<T> 和 PromiseRejectedResult,两者合起来就是 PromiseSettledResult<T>。直接写 .filter((r) => r.status === 'fulfilled'),老版本的 TS 推断不出过滤后的类型,后面访问 value 会报错,所以要写成 r is ... 这种类型守卫。 reason 的类型是 any,因为 JavaScript 里什么都能被 reject,不一定是 Error 对象。取 message 之前最好先判断一下 reason instanceof Error。

需要按位置对应时别过滤
如果三个结果分别对应页面上三个区块,就不要 filter,直接解构:const [user, orders, recs] = results,再分别看各自的 status。过滤之后下标就变了,没法知道哪一项对应哪个接口。
回答前,多想一步

容易答错的地方

以为失败项也有 value 字段
失败项只有 status 和 reason,没有 value。反过来,成功项也没有 reason。有人会写 r.value || r.reason 来取值,这样在兑现值是 0、空字符串时就会误取到 undefined。
在 Promise.allSettled 后面写 catch 处理失败
它返回的 Promise 总是兑现,catch 里永远收不到某一项的失败。失败信息必须从结果数组里按 status 找出来。
把 status 记成 resolved
status 的取值是 fulfilled 和 rejected,不是 resolved。resolved 在规范里的意思是「命运已经被锁定」,一个 Promise 被另一个还在 pending 的 Promise 决议时也叫 resolved,但它的状态还没定,所以不能拿来当状态名。
试着用自己的话回答

面试官还会怎么问?

手写 Promise.allSettled 怎么写?

对每一项调用 Promise.resolve(item).then(value => ({ status: 'fulfilled', value }), reason => ({ status: 'rejected', reason })),把失败也转成兑现,再把这些 Promise 交给 Promise.all。因为转换后没有任何一项会 reject,Promise.all 就会等到全部结束。

和 Promise.all 的结果有什么不同?

Promise.all 成功时结果数组里直接是兑现值,比如 [1, 2]。换成 Promise.allSettled,每一项都是描述对象,要多取一层 value。另外 Promise.all 遇到失败就整体拒绝,Promise.allSettled 永远兑现。

传入空数组会得到什么?

和 Promise.all([]) 一样,返回一个已经兑现、值为空数组的 Promise。

从一道题,走向一组知识

把知识连起来

异步与 Promise

已经拿到一个 Promise 了,为什么还用 new Promise 包一层是反模式?

想把一个回调接口塞进 Promise.allSettled 时才需要 new Promise,已经是 Promise 的直接放进去,别再包一层。

异步与 Promise

Promise.any 全部失败时会报什么错?每个失败原因怎么拿?

Promise.allSettled 把每个失败原因放在 reason 里,Promise.any 全部失败时则把所有原因收进 AggregateError 的 errors 数组。

参考资料

  • JavaScript:异步与 Promise参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 把四种输入的结果打印出来
  3. 拿到结果后怎么用
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑