You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何两个Promise未按顺序执行?解析第二个案例的暂停机制

Promise链式调用的执行顺序解析(针对案例2的异常输出)

案例1:符合预期的输出

Promise.resolve(1)
  .then((x) => console.log(1))
  .catch((x) => console.log(2))
  .then((x) => console.log(3));

Promise.reject(2)
  .then((x) => console.log(4))
  .then((x) => console.log(5))
  .catch((x) => console.log(6))
  .then((x) => console.log(7));

// 输出:1 3 6 7

案例2:看似异常的输出

Promise.resolve(1)
  .then((x) => console.log(1))
  .catch((x) => console.log(2))
  .then((x) => console.log(3));

Promise.reject(2)
  .then((x) => console.log(4))
  // .then((x) => console.log(5))
  .catch((x) => console.log(6))
  .then((x) => console.log(7));

// 输出:1 6 3 7

为什么第一个Promise的console.log(3)会被“延迟”?

核心原因是微任务队列的调度顺序和Promise链式调用的状态传递逻辑,拆解步骤如下:

  1. 同步代码执行阶段:微任务的初始入队

    • 第一个Promise链:Promise.resolve(1)是已完成(resolved)状态,它的第一个.then回调(console.log(1))会被加入微任务队列(记为任务A)。后续的.catch和.then只是注册回调,不会立即入队,因为它们依赖的上游Promise还未完成。
    • 第二个Promise链:Promise.reject(2)是已拒绝(rejected)状态,它的第一个.then只有成功回调,没有失败回调,所以这个.then会直接返回一个状态为rejected的新Promise。紧接着的.catch会捕获这个rejected状态,由于此时这个新Promise已经是rejected,.catch的回调(console.log(6))会被直接加入微任务队列(记为任务B)。

    此时微任务队列的顺序是:任务A → 任务B。

  2. 第一轮微任务执行

    • 先执行任务A:输出1。执行完成后,上游Promise状态变为resolved,跳过.catch,触发后续的.then回调(console.log(3)),将其加入微任务队列(记为任务C)。
    • 接着执行任务B:输出6。执行完成后,.catch返回一个resolved状态的Promise,触发后续的.then回调(console.log(7)),将其加入微任务队列(记为任务D)。

    此时微任务队列的顺序变为:任务C → 任务D。

  3. 第二轮微任务执行

    • 执行任务C:输出3。
    • 执行任务D:输出7。

对比案例1的差异

案例1中第二个Promise链多了一层.then((x) => console.log(5)),这层.then同样没有失败回调,会返回rejected状态的Promise,但它的存在会导致.catch的回调无法在同步阶段入队——只有当这层.then的上游Promise处理完成后,.catch的回调才会被加入微任务队列,而此时第一个Promise链的console.log(3)已经入队并执行,所以输出顺序是1 3 6 7。

内容的提问来源于stack exchange,提问作者Sergey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 19:24:53