微任务和宏任务有什么区别?
在前端开发中,微任务(Microtasks)和宏任务(Macrotasks)代表了两种不同的异步任务类型,它们在事件循环(Event Loop)中的执行时机和顺序有所不同。理解它们的区别对于编写高效且行为符合预期的 JavaScript 代码至关重要。
宏任务 (Macrotasks):
-
定义: 宏任务是浏览器发起的一些异步任务,它们通常包含:
setTimeout
setInterval
setImmediate
(Node.js 环境)requestAnimationFrame
(浏览器动画)- I/O 操作
- UI 渲染
- 用户交互事件 (例如:点击、滚动)
-
执行时机: 每一个宏任务执行完毕后,事件循环会检查微任务队列,并将所有在队列中的微任务执行完毕,然后再执行下一个宏任务。
微任务 (Microtasks):
-
定义: 微任务是 JavaScript 引擎自身发起的一些异步任务,它们通常包含:
Promise.then()
、Promise.catch()
、Promise.finally()
queueMicrotask()
MutationObserver
(监听 DOM 变化)
-
执行时机: 在当前宏任务执行完毕后,立即执行所有在微任务队列中的微任务,然后再执行下一个宏任务。这意味着在一个宏任务中,如果产生了新的微任务,这些微任务会在下一个宏任务开始之前被执行。
关键区别总结:
特性 | 宏任务 (Macrotasks) | 微任务 (Microtasks) |
---|---|---|
发起者 | 浏览器或 Node.js 环境 | JavaScript 引擎自身 |
典型示例 | setTimeout , setInterval , I/O , UI rendering |
Promise.then() , queueMicrotask() , MutationObserver |
执行时机 | 每个宏任务之后,执行所有微任务,然后执行下一个宏任务 | 当前宏任务之后,立即执行所有微任务 |
队列 | 宏任务队列 | 微任务队列 |
示例说明:
console.log('Start');
setTimeout(() => {
console.log('setTimeout');
}, 0); // 宏任务
Promise.resolve().then(() => {
console.log('Promise.then');
}); // 微任务
console.log('End');
输出结果为:
Start
End
Promise.then
setTimeout
解释:
Start
和End
同步执行并打印。setTimeout
和Promise.then
都是异步操作,被添加到各自的队列中。- 尽管
setTimeout
的延迟时间为 0,但它仍然是一个宏任务,会在当前宏任务 (主线程的同步代码) 执行完毕后才执行。 - 在当前宏任务执行完毕后,事件循环会检查微任务队列,发现
Promise.then
,于是先执行Promise.then
并打印Promise.then
。 - 最后,事件循环取出
setTimeout
这个宏任务并执行,打印setTimeout
。
理解微任务和宏任务的区别对于控制代码执行顺序、避免竞态条件以及编写高效的异步代码至关重要。 例如,在处理 UI 更新时,使用微任务可以确保在浏览器重新渲染之前完成所有必要的 DOM 操作,从而避免闪烁和性能问题。