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

JavaScript Promise执行顺序疑问:为何4先于2输出?

为什么Promise的then回调输出4早于2?

问题代码

let x = new Promise(function(resolve, reject) {
  setTimeout(() => resolve(1), 0);
})

x.then((res) => new Promise(function(resolve, reject){
    resolve(res*2);
}))
.then((res) => console.log(res))

x.then((res) => res*4)
.then((res) => console.log(res))

console.log("Out")

问题描述

为何代码输出顺序是 Out → 4 → 2,而非预期的 Out → 2 → 4?明明先调用了第一个then链,为什么第二个链的输出更早?

原因解析

核心在于Promise的then回调返回值类型不同,会导致后续回调进入微任务队列的时机不一样,结合JavaScript事件循环机制拆解如下:

  1. 同步代码优先执行
    首先执行最外层的console.log("Out"),所以第一个输出是Out。同时创建Promise实例x,并把setTimeout的回调(触发resolve(1))加入宏任务队列。

  2. 宏任务触发Promise状态变更
    同步代码执行完后,事件循环取出宏任务队列里的setTimeout回调执行,把x的状态改为resolved,此时两个绑定在x上的then回调都会被加入当前微任务队列。

  3. 微任务队列的分批次处理
    事件循环开始处理当前微任务队列:

    • 先执行第一个x.then的回调:这个回调返回了一个新的Promise实例。虽然这个新Promise的executor函数是同步执行的(立刻调用resolve(res*2)把状态设为resolved),但它的后续then回调(打印2的那个)不会加入当前微任务队列,而是要等当前微任务队列清空后,进入下一轮微任务队列。
    • 接着执行第二个x.then的回调:这个回调返回的是普通数值4,Promise会自动把这个值包装成状态为resolved的Promise,它的后续then回调(打印4的那个)会直接加入当前微任务队列。
  4. 微任务队列的执行顺序
    当前微任务队列里现在有打印4的回调,执行它 → 输出4。当前微任务队列清空后,事件循环检查到新的微任务队列里有打印2的回调,执行它 → 输出2。

所以最终输出顺序是:Out → 4 → 2。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 05:40:05