基于本文回答

播面 播面

刷题像听歌,多听自然懂
0
评论

宏任务 (MacroTask) 和 微任务 (MicroTask) 有什么区别?

知识点图片

在 JavaScript 的事件循环 (Event Loop) 机制中,宏任务 (MacroTask) 和微任务 (MicroTask) 是处理异步操作的两种不同类型的任务队列。

它们最核心的区别在于 执行时机优先级

1. 核心区别总结

  • 宏任务 (MacroTask):代表一个个独立的、离散的工作单元。浏览器完成一个宏任务后,通常会进行 UI 渲染,然后再执行下一个宏任务。
  • 微任务 (MicroTask):代表需要“立即”执行的小任务。它们会在当前宏任务结束后、UI 渲染之前、以及下一个宏任务开始之前全部执行完毕。

一句话口诀: 同步代码先执行,微任务紧跟其后清空队列,最后才轮到下一个宏任务。


2. 常见的任务分类

分类 浏览器环境常见 API Node.js 环境常见 API
宏任务 (MacroTask) setTimeout
setInterval
script (整体代码)
UI 渲染
I/O (网络请求完成等)
setImmediate
I/O 操作
微任务 (MicroTask) Promise.then / .catch / .finally
MutationObserver
process.nextTick (优先级最高)
Promise

3. 事件循环的执行流程

JavaScript 引擎会按照以下步骤循环执行:

  1. 执行栈 (Call Stack):执行主线程中的同步代码(这本身就是一个宏任务)。
  2. 清空微任务队列:当同步代码执行完毕(调用栈为空)时,检查微任务队列。如果有微任务,一次性全部执行完(包括在执行微任务过程中产生的新微任务)。
  3. UI 渲染:浏览器尝试进行页面重绘(如果需要)。
  4. 执行下一个宏任务:从宏任务队列中取出一个任务执行。
  5. 回到第 2 步

4. 代码示例与解析

请看下面的代码,试着预测输出顺序:

javascript
console.log('1. 脚本开始 (同步)');

setTimeout(() => {
  console.log('2. setTimeout (宏任务)');
}, 0);

Promise.resolve().then(() => {
  console.log('3. Promise 1 (微任务)');
}).then(() => {
  console.log('4. Promise 2 (微任务 - 链式)');
});

console.log('5. 脚本结束 (同步)');

正确输出顺序:

plaintext
1. 脚本开始 (同步)
5. 脚本结束 (同步)
3. Promise 1 (微任务)
4. Promise 2 (微任务 - 链式)
2. setTimeout (宏任务)

详细解析:

  1. 同步阶段

    • 执行 console.log('1...')
    • 遇到 setTimeout,将其回调函数放入 宏任务队列
    • 遇到 Promise.then,将其回调放入 微任务队列
    • 执行 console.log('5...')
    • 当前宏任务(Script 整体代码)执行完毕。
  2. 微任务阶段

    • 检查微任务队列,发现有 Promise 1。执行它,输出 3...
    • Promise 1 执行完后,触发了下一个 .then,将 Promise 2 加入微任务队列。
    • 队列还没空,继续执行 Promise 2,输出 4...
    • 微任务队列清空。
  3. 宏任务阶段

    • 从宏任务队列中取出 setTimeout 的回调。
    • 执行,输出 2...

5. 生活中的类比

想象你去银行办理业务(你是主线程):

  1. 宏任务:就像是排队办理业务的客户。柜员(JS 引擎)处理完一个客户(宏任务),可能会喝口水、看下时间(UI 渲染),然后叫下一个号。
  2. 微任务:就像是当前客户办完业务后,突然说:“啊,稍等,我还要顺便改个密码”。
    • 柜员不会让他重新排队(因为那样太慢了)。
    • 柜员会立刻帮他把这个小需求处理完(执行微任务),直到该客户所有的小需求都搞定,才会叫下一个客户(下一个宏任务)。

6. 为什么要区分这两者?

  • UI 渲染性能:微任务在渲染前执行,意味着你可以在微任务中更新数据,用户不会看到中间状态的闪烁。
  • 逻辑连贯性:微任务确保了某些异步操作(如 Promise)能尽可能快地执行,保持逻辑的紧密性,而不需要等待繁重的宏任务队列。
00:00
00:00