宏任务(Macrotask)和微任务(Microtask)是JavaScript事件循环中的两个重要概念。它们决定了JavaScript代码的执行顺序和时机。理解宏任务和微任务对于深入理解JavaScript的异步编程非常重要。
宏任务(Macrotask)
宏任务是指在事件循环中的一次完整的执行机会。常见的宏任务包括:
- 全局执行上下文(Global Execution Context)
- 定时器(Timers) :如
setTimeout和setInterval - I/O 操作
- UI 渲染
- 事件处理程序(Event Handlers) :如点击事件、键盘事件等
- Promise
微任务(Microtask)
微任务是指在当前宏任务执行完成后,但在控制权交给下一个宏任务之前执行的任务。常见的微任务包括:
- Promise
- MutationObserver
- Process.nextTick(Node.js 中)
- QueueMicrotask
事件循环(Event Loop)
事件循环是JavaScript引擎的核心机制之一,它决定了异步任务的执行顺序。事件循环的基本流程如下:
- 执行栈(Execution Context Stack) :存放当前正在执行的函数。
- 任务队列(Task Queue) :存放待执行的宏任务。
- 微任务队列(Microtask Queue) :存放待执行的微任务。
宏任务和微任务的执行顺序
-
执行当前宏任务:
- 当前宏任务执行完毕后,会清空当前微任务队列中的所有微任务。
- 微任务会在当前宏任务执行完毕后立即执行,但在此之前不会执行其他宏任务。
-
执行微任务:
- 微任务队列中的所有任务都会依次执行。
- 微任务执行完毕后,才会继续执行下一个宏任务。
示例代码
下面通过一个具体的示例来展示宏任务和微任务的执行顺序:
console.log('1');
setTimeout(() => {
console.log('2');
process.nextTick(() => {
console.log('3');
});
Promise.resolve().then(() => {
console.log('4');
});
}, 0);
process.nextTick(() => {
console.log('5');
});
Promise.resolve().then(() => {
console.log('6');
});
queueMicrotask(() => {
console.log('7');
});
console.log('8');
输出解析
-
全局执行上下文:
console.log('1'); console.log('8'); -
第一个
process.nextTick:process.nextTick(() => { console.log('5'); }); -
第一个
Promise的then:Promise.resolve().then(() => { console.log('6'); }); -
queueMicrotask:queueMicrotask(() => { console.log('7'); }); -
setTimeout内部的process.nextTick和Promise的then:setTimeout(() => { console.log('2'); process.nextTick(() => { console.log('3'); }); Promise.resolve().then(() => { console.log('4'); }); }, 0);
最终输出顺序
18567234
详细解释
-
全局执行上下文:
console.log('1');输出1。console.log('8');输出8。
-
第一个
process.nextTick:process.nextTick(() => { console.log('5'); });输出5。
-
第一个
Promise的then:Promise.resolve().then(() => { console.log('6'); });输出6。
-
queueMicrotask:queueMicrotask(() => { console.log('7'); });输出7。
-
setTimeout内部的process.nextTick和Promise的then:setTimeout(() => { console.log('2'); ... }, 0);输出2。process.nextTick(() => { console.log('3'); });输出3。Promise.resolve().then(() => { console.log('4'); });输出4。
总结
- 宏任务:包括
setTimeout、setInterval、事件处理程序等。 - 微任务:包括
Promise、MutationObserver、process.nextTick(Node.js)、queueMicrotask。 - 事件循环:先执行当前宏任务,然后清空当前微任务队列,再执行下一个宏任务。
通过理解宏任务和微任务的概念以及它们的执行顺序,可以更好地掌握JavaScript的异步编程机制。