promise.then 回调被精准调度进微任务队列,在当前宏任务结束后、下一个宏任务开始前集中执行;微任务包括promise.then/catch/finally回调、queuemicrotask()函数和mutationobserver回调,均由微任务队列统一管理并按fifo顺序清空执行。

Promise.then 不是“马上执行”,也不是“随便晚点执行”,而是被精准调度进微任务队列,在当前宏任务结束后、下一个宏任务开始前集中执行。这种机制让异步逻辑既可靠又可预测。
微任务队列里都有谁?
微任务(Microtask)是事件循环中优先级最高的异步任务类型,执行时机严格固定:每个宏任务结束之后、渲染之前,引擎会清空整个微任务队列,一个不剩地执行完。
- Promise.then / .catch / .finally 的回调函数——无论 Promise 是立刻 resolve 还是延迟 resolve,只要调用了 .then,回调就一定会进微任务队列
- queueMicrotask() —— 显式插入微任务的 API,行为与 Promise.then 一致
- MutationObserver 回调 —— 监听 DOM 变化时触发,也属于微任务
Promise.then 怎么进队?不是手动塞,而是自动注册
.then 方法本身是同步运行的,它立刻返回一个新的 pending Promise;但传入的回调函数不会立即执行,哪怕 Promise 已经 fulfilled。这是规范强制要求的异步保障,避免栈溢出和时序混乱。
用于 inference.sh 的 JavaScript/TypeScript SDK,可运行 AI 应用、构建代理、集成 150+ 模型。包名:@inferencesh/sdk(npm install),完整 TypeScript 支持。
- 如果 Promise 已 settled(fulfilled 或 rejected),调用 .then 时,引擎检测到状态已定,**立即把回调注册为微任务**,但不执行
- 如果 Promise 还在 pending 状态,.then 回调会被缓存;等后续 resolve/reject 触发时,再同步注册进微任务队列
- 注册动作是同步完成的,执行却要等到当前宏任务(比如整个 script 标签、click 事件处理函数)彻底退出调用栈
执行顺序怎么排?关键看“本轮清空”
事件循环不是“先微后宏”就完事了,而是每轮只取一个宏任务,执行完后必须清空全部微任务——哪怕新微任务在执行过程中又被加入,也要继续执行直到队列为空。
- 同步代码 → 微任务队列(全部清空)→ 渲染(可选)→ 下一个宏任务
- 链式调用中,
p.then(a).then(b)的 b 不会在 a 执行完的瞬间运行;a 返回值决定新 Promise 状态,b 作为新微任务,排在本轮或下一轮微任务队列尾部 - async/await 底层就是 Promise.then 的语法糖,await 后面的代码会被包装成 .then 回调,同样走微任务路径
为什么设计成这样?不只是为了“快”
微任务调度不是为了抢在 setTimeout 前面炫技,而是解决真实问题:
- 一致性:不管 Promise 创建方式如何(Promise.resolve() 或 new Promise + setTimeout),.then 行为完全一致
- 安全性:防止递归调用导致调用栈爆炸,所有 then 回调都脱离当前同步上下文
- 可组合性:链式调用、错误冒泡、Promise.all 等能力,全依赖微任务的 FIFO 和清空机制










