微任务队列在每个宏任务同步代码执行完毕后自动、连续清空,直至为空,期间不插入渲染或新宏任务;例如全局脚本(宏任务)输出'4'后立即执行所有已注册的promise.then('1'、'3'),再执行settimeout回调('2')。

微任务队列在每个宏任务执行完毕后自动清空,这是 JavaScript 运行时的规范行为,不需要手动干预。关键在于理解“执行完”的含义:它指的是当前宏任务的同步代码全部执行结束,并且控制权交还给事件循环时,引擎会立即、连续地执行微任务队列中的所有任务,直到队列为空。
什么是“宏任务执行完”
一个宏任务(如 script 初始化、setTimeout 回调、setInterval 回调、I/O 回调、UI 渲染 等)的“执行完”,是指其同步执行路径彻底结束——包括所有嵌套调用、同步语句、try/catch 的 finally 块都已运行完毕。此时 JS 引擎不会直接跳到下一个宏任务,而是先检查并执行微任务队列。
微任务队列如何被清空
事件循环在每次从宏任务队列中取出一个宏任务并执行后,会进入“微任务检查点”。该过程是自动、隐式且不可中断的:
- 引擎持续从微任务队列头部取出一个任务(如 Promise.then、MutationObserver 回调、queueMicrotask 注册的函数)并执行
- 如果该微任务内部又注册了新的微任务(例如在 then 中再次调用 Promise.resolve().then(...)),新任务会被追加到当前微任务队列尾部
- 引擎继续执行,直到队列长度变为 0 才停止
- 这个过程是“本轮循环内完成”的,不会让出控制权给渲染或下一个宏任务
一个典型执行顺序示例
以下代码能清晰体现清空机制:
Promise.resolve().then(() => console.log('1'));setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
输出为:4 → 1 → 3 → 2。原因:全局 script 是第一个宏任务;打印 '4' 后同步结束 → 引擎立即执行两个 Promise.then(微任务),按注册顺序输出 '1' 和 '3' → 微任务队列变空 → 才轮到 setTimeout 的宏任务,输出 '2'。
注意边界情况
微任务清空不发生在异步操作“触发时”,而是在其所属宏任务“真正结束时”:
- async/await 函数内部的 await 并不会导致微任务队列提前清空;它只是暂停当前 async 函数的执行,但整个 async 函数体仍属于同一个宏任务上下文
- 在事件处理器(如 click 回调)中抛出未捕获异常,微任务仍会在 try/catch 或事件系统处理完该异常后清空(规范要求错误不影响微任务调度)
- Node.js 中 process.nextTick() 属于微任务,但优先级高于 Promise.then;不过它同样遵循“本轮宏任务结束后立即、连续执行至空”的规则
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











