微任务检查点是JavaScript引擎在每次宏任务执行完毕后立即清空微任务队列的内置机制。它严格遵循规范,在全局脚本、setTimeout、Promise回调、I/O及UI事件处理结束后触发,确保DOM渲染前微任务全部执行完毕,且新微任务会加入当前队列并本轮执行。

JavaScript 引擎在每次事件循环(Event Loop)的宏任务(macrotask)执行完毕后,会立即执行所有已排队的微任务(microtasks),这个过程就是“微任务检查点”(Microtask Checkpoint)。它不是由开发者手动触发的机制,而是引擎内置的、严格遵循规范(ECMAScript 和 HTML)的调度行为。
微任务检查点发生的时机
它发生在以下每个宏任务执行结束之后,且在控制权交还给浏览器渲染或下一个宏任务之前:
- 全局脚本执行完成
- setTimeout / setInterval 回调执行完
- Promise.then/catch/finally 回调(本身是微任务,但其内部产生的新微任务也会被本轮检查点捕获)
- I/O 回调(如 Node.js 中的 fs.readFile 回调)
- UI 事件处理函数(如 click、input)执行完毕
微任务队列如何被刷新
引擎维护一个单独的微任务队列(FIFO),每次检查点启动时,会持续从队列头部取出任务执行,直到队列为空。关键点在于:
- 新加入的微任务(比如在 Promise 处理器中又调用 Promise.resolve().then(...))会被追加到当前队列末尾,并在本轮检查点中继续执行
- 不会因为队列变长而中断;只要队列非空,就一直清空,哪怕导致长时间阻塞(即“微任务风暴”,应避免)
- DOM 渲染(paint)一定发生在微任务队列完全清空之后,这也是为什么用 Promise.then 能拿到最新 DOM 状态
和宏任务队列的区别
微任务检查点与宏任务调度是正交的:
- 宏任务队列按顺序一次只取一个(如先执行 script,再执行 setTimeout 回调),中间插入完整的微任务检查点
- 微任务队列没有“轮次”概念——它只属于上一个宏任务的收尾阶段,不跨宏任务保留未执行项
- queueMicrotask()、Promise.then、MutationObserver 回调都进入同一个微任务队列,按入队顺序执行,无优先级区分
实际例子说明执行顺序
下面代码能清晰体现检查点行为:
console.log(1); Promise.resolve().then(() => console.log(2)); setTimeout(() => console.log(3), 0); Promise.resolve().then(() => console.log(4)); console.log(5);
输出为:1 → 5 → 2 → 4 → 3。原因:同步代码(1、5)先执行;随后触发微任务检查点,运行两个 Promise 回调(2、4);等微任务队列清空,才从宏任务队列取 setTimeout(3)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











