Promise 的 then 回调总是异步执行:pending 状态时暂存于私有反应记录数组,fulfilled/rejected 状态时直接入微任务队列;链式调用返回的新 Promise 依回调返回值决定状态与调度时机。

Promise 内部的 then 回调函数不是“立即执行”,而是被**异步暂存**,等 Promise 状态确定后,再按注册顺序排队执行。
回调存放在微任务队列中
当调用 promise.then(onFulfilled, onRejected) 时,如果 Promise 当前状态还是 pending,两个回调函数会被封装成“作业”(job),放入一个内部的回调数组(比如叫 [[PromiseFulfillReactions]] 或 [[PromiseRejectReactions]]),等待后续触发。
- 这个存储结构是 Promise 实例私有的,规范里叫“反应记录(Reaction Records)”,每个记录包含回调、this 值、参数处理逻辑等
- 浏览器/引擎实现上,通常用数组或链表维护这些待执行的回调
- 状态变为
fulfilled或rejected后,对应数组里的所有回调会被取出,包装成微任务(microtask),由事件循环在当前宏任务结束后统一调度
状态已确定时,回调直接入队微任务
如果 Promise 已经是 fulfilled 或 rejected 状态,then 调用不会把回调存进内部数组,而是立刻创建微任务(如 queueMicrotask 或 PromiseJobs),把回调推入微任务队列。
- 例如:
const p = Promise.resolve(42); p.then(console.log);→ 回调不存、直接排队 - 这种设计保证了无论 Promise 是否已决议,
then的行为都是一致的:总是异步执行
链式调用中的回调存放逻辑
每次 then 都返回新 Promise,新 Promise 的状态取决于回调的返回值或抛出的错误。它的回调同样遵循上述规则——先暂存,等上游 Promise 完成后再决定何时执行。
- 返回值是普通值 → 新 Promise 立即
fulfilled,回调入微任务队列 - 返回另一个 Promise → 新 Promise 等待它决议,回调暂存在该 Promise 的反应数组中
- 回调抛错 → 新 Promise 立即
rejected,错误回调(如果有)被暂存或入队
你不需要手动管理这些存放逻辑
ECMAScript 规范和主流引擎(V8、SpiderMonkey 等)已完整实现这套机制。开发者只需按需写 then,引擎会自动处理回调的暂存、调度与清理。
- 调试时可通过
console.log+Promise.resolve().then(...)对比观察微任务执行时机 - 想查看内部状态?现代 DevTools 的 Promise 调试支持(如 Chrome 的 “Async Stack Trace”)可辅助追踪
- 避免在
then中做同步阻塞操作,否则会影响微任务队列的及时消费


















