前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
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 传一个空数组进去,会一直 pending 吗?

不会。Promise.all([]) 返回一个已经 fulfilled 的 Promise,值是空数组 []。它不会一直 pending,也不会 reject,只是 then 回调照样要等同步代码跑完才执行。

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

零个任务也算全部成功

  1. 计数器Promise.all 内部数还剩几个没完成,空数组一开始就是 0
  2. 同步 fulfilled计数为 0 时当场用 [] 兑现,不用等任何任务
  3. 微任务回调then 注册的回调总是异步执行,同步代码先跑完

业务里用 ids.map(request) 拼任务时,空列表会让 Promise.all 秒成功,下游拿到空数组。要不要当成异常,得自己判断,不要指望它报错。

核心回答

先记住这个答案

Promise.all([]) 会返回一个已经 fulfilled 的 Promise,兑现值是空数组 [],不会一直 pending,也不会报错。道理很简单:Promise.all 的语义是「所有任务都成功就成功」,一个任务都没有,自然算全部成功。要注意的是,状态虽然当场就定下来了,但 then 里的回调依然是异步执行的,同步代码先跑完才轮到它。

  • Promise.all([]) 立刻 fulfilled,值是 []
  • 状态是同步定下的,then 回调仍在微任务里执行
  • Promise.race([]) 才会永远 pending
  • Promise.any([]) 直接以 AggregateError 拒绝

四个组合方法遇到空数组

面试官问完 Promise.all,经常顺手问另外三个。放在一起看最好记。

同一个空数组,四种结果JavaScript
Promise.all([]).then((res) => console.log('all', JSON.stringify(res)))
Promise.race([]).then(() => console.log('race 永远不会打印'))
Promise.any([]).catch((err) => console.log('any', err.name))
Promise.allSettled([]).then((res) => console.log('allSettled', JSON.stringify(res)))
console.log('同步代码结束')
查看输出与解释
同步代码结束
all []
any AggregateError
allSettled []

先打印「同步代码结束」,说明回调都是异步的。Promise.all 和 Promise.allSettled 都拿到空数组。Promise.any 的语义是「有一个成功就成功」,一个任务都没有,就不可能有人成功,所以直接以 AggregateError 拒绝。Promise.race 是「谁先落定听谁的」,没有参赛选手,比赛永远不会结束,返回的 Promise 就一直 pending,then 永远不会执行。 记的时候可以这样想:「全部」类的 Promise.all 和 Promise.allSettled 对空集合直接成功,「至少一个」类的 Promise.any 对空集合直接失败,而 Promise.race 压根没有答案。

为什么说状态是同步定下的

Promise.all 内部维护一个计数器,记录还有几个任务没完成。每有一个任务兑现,计数就减一,减到 0 时用结果数组兑现返回的 Promise。空数组遍历完,计数器一开始就是 0,所以在 Promise.all([]) 这一行执行的当下,返回的 Promise 就已经是 fulfilled 了。

和 [1] 对比一下JavaScript
// 和一个已兑现的普通值赛跑,谁先赢说明谁先落定
const probe = (p) => Promise.race([p, '还在 pending'])
probe(Promise.all([])).then((v) => console.log('空数组:', JSON.stringify(v)))
probe(Promise.all([1])).then((v) => console.log('[1]:', JSON.stringify(v)))
查看输出与解释
空数组: []
[1]: "还在 pending"

空数组那个 Promise 在赛跑开始前就已经兑现,排在「还在 pending」前面赢了。Promise.all([1]) 不一样,它要先把 1 包成 Promise.resolve(1),再通过 then 等它兑现,这一步要走一次微任务,所以赛跑时它还没落定,输给了普通值。 这个区别平时写业务基本碰不到,因为你拿结果只能通过 then 或 await,两种情况都是异步拿到的。面试时说清「状态同步确定,回调异步执行」这两层就够了。

回答前,多想一步

容易答错的地方

以为空数组会让 Promise.all 一直等下去
会一直等的是 Promise.race([]),不是 Promise.all([])。把两者搞混,是这道题最常见的错。
以为状态是 fulfilled 就能同步拿到值
Promise 没有同步读取结果的 API,就算它已经兑现,then 回调和 await 后面的代码也要等当前同步代码执行完才运行。const res = Promise.all([]) 拿到的是 Promise 对象,不是 []。
把空结果当成接口出错
比如根据勾选的 id 批量删除,用户一个都没勾,Promise.all([]) 立刻成功,界面提示「删除成功」。这不是 Promise.all 的问题,是调用前没判断列表是否为空。
试着用自己的话回答

面试官还会怎么问?

传的不是数组,而是 undefined 会怎样?

Promise.all 要求参数可迭代。传 undefined、数字这类不可迭代的值,它不会同步抛错,而是返回一个以 TypeError 拒绝的 Promise。所以要在 catch 里处理,而不是在外面包 try。

传一个字符串 'abc' 呢?

字符串是可迭代的,会被拆成三个单字符的普通值,结果是 ['a', 'b', 'c']。这属于合法但没什么用的写法,面试里能说出「只要可迭代就行,不限于数组」就可以。

自己手写 Promise.all 时,空数组要怎么处理?

手写版常见的写法是在每个任务兑现时计数,等计数等于长度再 resolve。空数组根本不会进入循环,计数永远等不到,返回的 Promise 就一直 pending。所以要在循环前加一句:长度为 0 时直接 resolve([])。这是手写题里很容易被扣分的边界。

从一道题,走向一组知识

把知识连起来

异步与 Promise

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

空数组是一个值都没有,数组里放普通值时 Promise.all 也能处理,但兑现时机会晚一点。

异步与 Promise

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

空数组不可能失败,有任务时只要一个 reject,Promise.all 就立刻整体失败。

异步与 Promise

Promise.resolve 传入一个 thenable 对象时会发生什么?

Promise.all 内部对每一项调用 Promise.resolve,弄懂它怎么处理 thenable 就知道每一项是怎么被等待的。

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

参考资料

  • Promise.all()

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

本题目录
  1. 先记住这个答案
  2. 四个组合方法遇到空数组
  3. 为什么说状态是同步定下的
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

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

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