Promise.then 回调在调用 .then 时根据 Promise 当前状态决定入队时机:已 settled 则立即注册微任务,pending 则缓存待状态变更后注册;微任务总在当前宏任务结束后统一执行。

Promise.then 的回调函数不是在 Promise 创建时、也不是在 resolve 调用瞬间进入微任务队列,而是在 调用 .then 方法的那一刻,由 JavaScript 引擎根据当前 Promise 的状态决定是否立即注册为微任务。
调用 .then 时 Promise 已 settled(fulfilled/rejected)
此时回调函数会同步注册进微任务队列,但不会立刻执行——它要等到当前宏任务(如整个 script 脚本、事件处理函数)完全执行完毕后才运行。
- 例如
Promise.resolve(42).then(x => console.log(x)):Promise 创建即 fulfilled,.then 被调用时引擎立刻将回调排入微任务队列 - 注意:
.then方法本身是同步执行的,它返回一个 pending 状态的新 Promise,但回调的调度被规范强制异步化 - 这是最常见也最高效的“高优异步”写法,等效于
queueMicrotask(() => {...})
调用 .then 时 Promise 仍处于 pending 状态
回调不会马上入队,而是被暂存到该 Promise 内部的 [[PromiseFulfillReactions]] 或 [[PromiseRejectReactions]] 列表中,等待状态变更触发。
- 例如
new Promise(r => {}).then(x => console.log(x)):构造函数里没调 resolve,Promise 保持 pending,.then 只缓存回调,不入队 - 后续若调用
resolve(100),引擎会遍历缓存列表,把所有匹配的 onFulfilled 回调同步注册进当前微任务队列 - 即使 resolve 是同步调用(如
new Promise(r => r(1)).then(...)),回调也仍走“注册→等待清空”流程,确保行为一致
链式调用中后续 .then 的入队时机
每个 .then 返回的新 Promise 的状态,直接决定下一个 .then 回调能否入队以及何时入队。
- 前一个回调返回普通值(如
return 'ok')→ 新 Promise 立即 fulfilled → 下一个.then回调立刻注册进微任务队列 - 前一个回调返回 Promise(如
return fetch('/api').then(...))→ 新 Promise 状态取决于该返回 Promise → 下一个.then回调要等它 settled 后才注册 - 多个
.then在同一轮微任务中注册,按 FIFO 顺序执行,不会交叉或插队
和宏任务的关键执行顺序对比
微任务队列总在每个宏任务结束之后、下一个宏任务开始之前**被一次性清空,这是理解输出顺序的核心。
- 典型顺序:同步代码 → 微任务队列(全部执行完)→ 渲染(可选)→ 下一个宏任务(如 setTimeout 回调)
- 示例:
console.log(1); Promise.resolve().then(() => console.log(2)); setTimeout(() => console.log(3), 0); console.log(4);输出为1 → 4 → 2 → 3 - 哪怕 Promise 是异步 resolve 的,只要
.then在它 settled 后调用,回调就属于本轮微任务;若在 pending 时调用,则属于下一轮(取决于 resolve 触发时机)


















