前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
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.all 快速失败
JavaScript异步与 Promise

Promise.all 有一个 reject 了,会立刻失败吗?剩下的任务还会跑吗?

会立刻失败。第一个 reject 出现时,Promise.all 就以这个错误拒绝,不再等其他任务。但剩下的任务不会被停掉,它们照样执行完,只是结果没人要了,后面再有的错误也会被悄悄吞掉。

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

快速失败只是不等了,不是叫停

  1. 快速失败第一个拒绝原因直接成为 Promise.all 的拒绝原因
  2. 任务继续执行Promise 创建时任务就已开始,Promise.all 管不到它们
  3. 后续错误被吞Promise.all 给每项都挂了处理函数,后面的 reject 不会报警

「第一个」指的是最先 reject 的那个,不是数组里排第一的那个。数组第一项还在等、第三项先失败,拿到的就是第三项的错误。

核心回答

先记住这个答案

会立即拒绝。Promise.all 只要看到任何一项 reject,就用这个错误拒绝自己,不再等其他项。但其他任务并不会被停止,它们在创建 Promise 的时候就已经开始执行了,Promise.all 只是不再收集它们的结果。之后即使别的任务也失败了,这些错误也会被默默忽略,不会触发未处理拒绝的警告。

  • 第一个 reject 出现,Promise.all 立刻拒绝
  • 其他任务照样执行,结果被丢弃
  • 后续的 reject 被忽略,不会报未处理错误
  • 想真正停掉剩余请求,要用 AbortController

看一下执行顺序

三个任务分别在 30、10、20 毫秒后完成,其中 B 和 C 都会失败。

一个失败后,其他任务还在跑JavaScript
const task = (name, ms, fail) =>
  new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(name, '执行完')
      fail ? reject(new Error(name + ' 失败')) : resolve(name)
    }, ms)
  })

Promise.all([task('A', 30), task('B', 10, true), task('C', 20, true)])
  .then((res) => console.log('then', res))
  .catch((err) => console.log('catch', err.message))
查看输出与解释
B 执行完
catch B 失败
C 执行完
A 执行完

10 毫秒时 B 失败,catch 马上执行,打印「catch B 失败」,这就是快速失败。但 C 和 A 的定时器没有被取消,后面照样打印「执行完」。C 也 reject 了,可是 Promise.all 早就落定了,Promise 的状态一旦改变就不会再变,所以 C 的错误没有任何效果。 为什么 C 的错误没有报「未处理的拒绝」?因为 Promise.all 一开始就给每一项都挂了成功和失败两个处理函数,C 的拒绝其实是被处理过的,只是处理的结果被丢掉了。

怎么真正停掉剩下的请求

真实项目里,其他任务通常是网络请求。一个失败了,剩下的请求还在占带宽、占服务端资源。如果剩下的结果已经没用了,可以用 AbortController 主动取消。

共用一个 signal,失败时一起取消JavaScript
async function loadAll(urls) {
  const controller = new AbortController()
  try {
    return await Promise.all(
      urls.map((url) =>
        fetch(url, { signal: controller.signal }).then((res) => {
          if (!res.ok) throw new Error(`${url} 返回 ${res.status}`)
          return res.json()
        })
      )
    )
  } catch (err) {
    controller.abort() // 第一个错误到这里时,把还没回来的请求全部取消
    throw err
  }
}

所有请求共用同一个 controller.signal。任意一个失败,Promise.all 拒绝,进入 catch,调用一次 abort(),其他还在路上的 fetch 就会以 AbortError 拒绝,浏览器也会断开这些连接。这些 AbortError 同样会被 Promise.all 忽略,不会覆盖最初那个错误。 注意 fetch 只有网络失败才会 reject,HTTP 500 这类响应是正常兑现的,所以要自己判断 res.ok 并抛错,否则快速失败根本不会触发。

回答前,多想一步

容易答错的地方

以为「第一个」指数组里的第一项
Promise.all 拿到的是时间上最先 reject 的那个错误,和它在数组里排第几无关。上面的例子里 B 排第二,但它最先失败,拿到的就是 B 的错误。
以为 Promise.all 拒绝后,其他任务就停了
Promise 本身没有取消的能力。任务在创建 Promise 时就开始了,Promise.all 拒绝只是不再等待,其他任务会完整执行,包括它们的副作用,比如写数据库、发埋点。
以为能拿到所有失败的原因
Promise.all 只给出第一个错误,后面的全部丢弃。要知道所有失败原因,改用 Promise.allSettled,它会等所有任务结束,把每一项的结果都告诉你。
试着用自己的话回答

面试官还会怎么问?

如果想等全部结束再统一报错,怎么写?

用 Promise.allSettled 等所有任务落定,再筛出 status === 'rejected' 的项。如果有失败,可以把所有 reason 收集起来,抛一个 AggregateError 出去,调用方就能一次看到全部错误。

手写 Promise.all 时,快速失败怎么实现?

每一项都 Promise.resolve(item).then(onFulfilled, reject),把外层 Promise 的 reject 直接作为每一项的失败回调。第一个失败的调用 reject 让外层落定,后面再调用 reject 什么也不会发生,因为 Promise 的状态只能改变一次。所以快速失败和「后续错误被忽略」是同一个机制带来的。

await 多个请求时,一个一个写 await 会有同样的问题吗?

会有另一种问题。const a = await p1; const b = await p2 如果 p2 先 reject,而此时代码还卡在 await p1,这时 p2 的拒绝暂时没有处理函数,可能触发未处理拒绝的警告。Promise.all 一次性给所有项挂上处理函数,就没有这个问题。

从一道题,走向一组知识

把知识连起来

异步与 Promise

Promise.all 的数组里混了普通值,会怎么处理?

数组里的普通值会被包成已兑现的 Promise,永远不会触发快速失败,能触发的只有真正会 reject 的项。

异步与 Promise

new Promise 里传的函数是同步执行还是异步执行?

new Promise 时 executor 同步执行,任务在交给 Promise.all 之前就已经跑起来了,所以快速失败停不掉它们。

放回知识体系中复习JavaScript 进阶知识

参考资料

  • Promise.all()

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

本题目录
  1. 先记住这个答案
  2. 看一下执行顺序
  3. 怎么真正停掉剩下的请求
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

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

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