前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
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 then 触发顺序
JavaScript异步与 Promise

多个 Promise 并发执行时,then 回调一定按完成顺序触发吗?

Promise 一兑现,它的 then 回调就进微任务队列,所以谁先兑现谁的回调先执行,和创建顺序、注册顺序无关。例外是用另一个 Promise 去 resolve 时,要多等两个微任务才算真正兑现。

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

决定回调顺序的三件事

  1. 兑现时机resolve 真正生效的那一刻,回调才被放进微任务队列
  2. 微任务队列先进先出,同一个 Promise 的多个回调按注册顺序执行
  3. 嵌套 resolveresolve 的参数是 Promise 时要先展开它,多花两个微任务

网络请求谁先返回由服务端和网络决定,代码里无法保证,所以不能拿 then 的执行顺序当业务顺序用。

核心回答

先记住这个答案

基本是按完成顺序。一个 Promise 兑现时,它身上登记过的 then 回调会被放进微任务队列,所以先兑现的先执行,跟 Promise 是先创建还是后创建、then 是先写还是后写都没关系。但有一个常见例外:用一个 Promise 去 resolve 另一个 Promise,外层要多等两个微任务才兑现,看起来就像「先完成的反而后执行」。另外 Promise.all 返回的数组永远按输入顺序排列,不反映谁先完成。

  • 回调在 Promise 兑现那一刻才进微任务队列
  • 同一轮兑现的,按进队顺序执行
  • resolve 一个 Promise 会晚两个微任务兑现
  • Promise.all 结果按输入顺序,不按完成顺序

三个定时器看完成顺序

下面三个 Promise 按 a、b、c 的顺序创建,then 也按这个顺序注册,但定时器的时间不一样。

创建顺序和完成顺序不一致JavaScript
const delay = (name, ms) => new Promise((r) => setTimeout(() => r(name), ms))

const a = delay('a', 30)
const b = delay('b', 10)
const c = delay('c', 20)

a.then((v) => console.log('完成', v))
b.then((v) => console.log('完成', v))
c.then((v) => console.log('完成', v))
Promise.all([a, b, c]).then((list) => console.log('all', JSON.stringify(list)))
查看输出与解释
完成 b
完成 c
完成 a
all ["a","b","c"]

then 只是在 Promise 上登记一个回调,并不会让它排队。b 在 10 毫秒时兑现,这一刻它的回调才进入微任务队列并马上执行,所以 b 最先打印。a 最晚兑现,排在最后。 Promise.all 等三个都兑现后才执行,结果数组是 ["a","b","c"],按传入的位置放,不是按完成时间放。所以要拿到有序结果,用 Promise.all 就够了,不用自己排序。

例外:用 Promise 去 resolve 会晚两拍

同一轮同步代码里兑现的多个 Promise,理论上按兑现的先后执行。但「兑现」这个时间点有时比你以为的晚。

先创建的反而后打印JavaScript
const p1 = new Promise((r) => r(Promise.resolve('p1'))) // 参数是 Promise
const p2 = Promise.resolve('p2') // 参数是普通值

p1.then((v) => console.log(v))
p2.then((v) => console.log(v))
查看输出与解释
p2
p1

p2 立刻就兑现了。p1 的 resolve 收到的是一个 Promise,它得先调用这个 Promise 的 then 来展开(第一个微任务),展开后的结果再通过回调传回来(第二个微任务),p1 才真正兑现。这一来一回,p1 的回调就排到了 p2 后面。 async 函数里 return 一个 Promise 也是同样的道理,所以 async () => somePromise 和 async () => 1 放在一起跑,前者的结果会晚出来。

已经兑现的 Promise 再调 then
如果 Promise 早就兑现了,这时调用 then,回调会在调用 then 的那一刻进队列。所以对一堆已经兑现的 Promise 来说,执行顺序就等于 then 的调用顺序。这也是题目里「按调用顺序」那种说法的来源,它只在这个前提下成立。
回答前,多想一步

容易答错的地方

说 then 回调按注册顺序执行
只有同一个 Promise 上的多个回调才按注册顺序执行。不同 Promise 之间看的是谁先兑现,注册顺序不起作用。上面三个定时器的例子就是反例。
说 Promise.all 的结果按完成顺序排
Promise.all 内部给每一项记了下标,某一项兑现时把值写到对应下标上,所以结果顺序和输入数组一致。想按完成顺序处理,要自己给每个 Promise 挂 then,或者用 Promise.race 反复取最快的那个。
在业务里依赖请求返回顺序
两个接口先发的不一定先回。比如搜索框连续输入,旧请求慢了就会覆盖新结果。这种问题要靠取消旧请求或者比对请求序号来解决,而不是指望 then 的顺序。
试着用自己的话回答

面试官还会怎么问?

想让并发请求按完成顺序逐个渲染,怎么写?

给每个请求单独挂 .then(render) 就行,谁先回谁先渲染。如果还要在全部完成后做收尾,再用 Promise.allSettled 等所有请求结束,这样某个请求失败也不影响其它结果展示。

setTimeout 回调和 then 回调谁先执行?

then 回调是微任务,setTimeout 回调是宏任务。每执行完一个宏任务,引擎会先清空微任务队列,再取下一个宏任务。所以同一轮里注册的,then 总是先于 setTimeout 执行。

同一个 Promise 上挂了两个 then,执行顺序确定吗?

确定,按注册顺序执行。Promise 内部维护一个回调列表,兑现时按列表顺序依次放进微任务队列。这个顺序是规范保证的,可以依赖。

从一道题,走向一组知识

把知识连起来

异步与 Promise

Promise 已经兑现了,then 回调为什么还是异步执行?

then 回调为什么进微任务队列,是理解这里执行顺序的前提。

异步与 Promise

怎么用 Promise.race 给异步操作加超时?超时后原来的 Promise 还会跑吗?

Promise.race 拿的就是最先兑现的那个结果,是完成顺序最直接的应用。

参考资料

  • JavaScript:异步与 Promise参考资料

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

本题目录
  1. 先记住这个答案
  2. 三个定时器看完成顺序
  3. 例外:用 Promise 去 resolve 会晚两拍
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

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

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