event loop 中 promise 微任务并非“插队”,而是严格在当前宏任务结束后、下一轮宏任务开始前清空微任务队列,故 promise.then 总在 settimeout 之前执行。

Event Loop 分析 Promise 微任务“插队”,关键不在“插队”本身,而在微任务队列的执行时机——它总在当前同步任务结束后、下一轮宏任务开始前立即清空,所以看起来像“插在中间”。
微任务不是插队,是固定插入点
所谓“插队”,其实是误解。Promise.then() 回调被放入微任务队列(microtask queue),而 Event Loop 的执行规范明确要求:每次执行完一个宏任务(如 setTimeout 回调、事件处理函数、script 脚本)后,必须同步、连续、全部执行完当前微任务队列中的所有任务,之后才去取下一个宏任务。
这导致效果上:哪怕 Promise 在 setTimeout 之后创建,它的 then 回调仍会在 setTimeout 的回调之前执行——因为 setTimeout 是宏任务,而 Promise.then 是微任务,属于“本轮循环尾部”,而非“下一轮开头”。
典型代码验证执行顺序
看这段代码:
console.log('1');setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
输出是:1 → 4 → 3 → 2。原因如下:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 同步代码依次执行:'1'、'4'
- 宏任务队列加入一个 setTimeout 回调(延迟 0ms,但仍是宏任务)
- 微任务队列加入一个 Promise.then 回调
- 当前宏任务(整个 script)结束 → 立即清空微任务队列 → 输出 '3'
- 回到 Event Loop,取下一个宏任务 → 执行 setTimeout 回调 → 输出 '2'
多个微任务会排队,不会被中断
微任务队列是 FIFO 队列,且一旦开始执行,就全部跑完,中途不穿插宏任务或新同步代码。例如:
Promise.resolve().then(() => {console.log('a');
Promise.resolve().then(() => console.log('b'));
});
Promise.resolve().then(() => console.log('c'));
输出一定是:a → c → b。因为:
- 初始两个 then 被加入微任务队列:[then-a, then-c]
- 执行 then-a → 输出 'a',内部又加了一个 then-b → 微任务队列变为 [then-c, then-b]
- 继续执行 then-c → 输出 'c'
- 再执行 then-b → 输出 'b'
注意:then-b 是在 then-a 执行中动态加入的,但它仍排在当前轮微任务队列末尾,不会打断已开始的微任务执行流。
与 MutationObserver 的协同关系
MutationObserver 回调也属于微任务,和 Promise.then 共享同一微任务队列(在大多数浏览器中)。这意味着:
- 它们按加入顺序混合排队,不分类型优先级
- 比如先注册 MO,再 resolve Promise,那么 MO 回调会排在 Promise.then 前面
- 但实际开发中极少需要跨类型协调,Promise 已足够覆盖绝大多数异步编排场景
不必刻意用 MO 替代 Promise,除非你需要监听 DOM 变化并保证其响应时机与 Promise 一致。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










