微任务在事件处理链条后执行,是因为 javascript 引擎将宏任务(如 ui 渲染、用户交互)和微任务(如 promise 回调、mutationobserver)分成了不同的队列,并在每个宏任务结束后清空微任务队列。具体做法是:当宏任务执行完毕后,引擎会检查微任务队列是否为空,如果不为空,则依次执行所有微任务,直到队列为空,然后再进行下一轮宏任务的调度。

为什么微任务会在宏任务之后执行?
微任务之所以在宏任务之后执行,是因为 JavaScript 的事件循环机制规定,在每个宏任务执行完成后,必须立即处理完当前所有的微任务,才能继续下一个宏任务。这种设计确保了微任务的高优先级,使得像 Promise 这样的异步操作能够尽快得到处理,而不会受到其他宏任务的干扰。

console.log('Start');
setTimeout(() => {
console.log('Timeout');
}, 0);
Promise.resolve().then(() => {
console.log('Promise');
});
console.log('End');
预期输出:
Start
End
Promise
Timeout
微任务队列是如何被调度的?
微任务队列的调度是在每个宏任务执行完毕后进行的。当宏任务执行完成后,JavaScript 引擎会检查微任务队列,如果队列中有待执行的微任务,则会依次执行这些微任务,直到队列为空。这个过程是同步的,意味着在当前宏任务结束之前,所有微任务都会被执行完毕。只有当微任务队列为空时,才会进入下一轮宏任务的调度。
你是 TypeScript 项目架构专家,专注于脚手架搭建生产就绪的 Node.js 和前端应用。生成包含现代工具链(pnpm、Vite、Next.js)、类型

function scheduleMicrotask() {
const microtasks = [];
function enqueueMicrotask(task) {
microtasks.push(task);
}
function processMicrotasks() {
while (microtasks.length > 0) {
const task = microtasks.shift();
task();
}
}
// 模拟宏任务执行
function runMacroTask() {
console.log('Macro Task Start');
// 执行宏任务逻辑
console.log('Macro Task End');
// 执行微任务
processMicrotasks();
}
// 添加微任务
enqueueMicrotask(() => console.log('Microtask 1'));
enqueueMicrotask(() => console.log('Microtask 2'));
// 运行宏任务
runMacroTask();
}
scheduleMicrotask();
预期输出:
Macro Task Start
Macro Task End
Microtask 1
Microtask 2
如果在微任务中再次添加微任务会发生什么?
如果在微任务中再次添加微任务,新添加的微任务会被加入到当前微任务队列的末尾,并在当前所有已存在的微任务执行完毕后继续执行。这意味着微任务可以递归地触发新的微任务,形成一个链式调用。只要微任务队列不为空,引擎就会持续处理这些微任务,直到队列为空。这种行为确保了微任务的高优先级和快速响应特性。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










