JavaScript中的宏任务和微任务

213 阅读1分钟

前提

JavaScript是单线程的,即一次只能执行一个任务。

因此为了处理异步操作,比如定时器、网络请求,就有了事件循环机制,它是是其处理异步任务的核心,来确保单线程环境下的高效运行,防止阻塞线程。

事件循环的主要组成部分:调用栈(Call Stack)、任务队列(Task Queue)、微任务队列(Microtask Queue),还有浏览器提供的Web APIs。

  • 调用栈(Call Stack) :执行同步代码,遵循后进先出。

  • Web APIs:浏览器提供的异步功能(如 setTimeoutfetch)。

而那宏任务微任务就是任务队列中的不同类型任务。

宏任务

  • 由宿主环境(浏览器、Node.js)发起的任务。

  • 常见类型

    • setTimeout / setInterval
    • I/O 操作(如文件读写)
    • DOM 事件回调(如点击事件)
    • requestAnimationFrame(浏览器)
    • setImmediate(Node.js)

微任务

  • 由 JavaScript 自身发起的任务

  • 常见类型

    • Promise.then() / Promise.catch()
    • MutationObserver(监听 DOM 变化)
    • queueMicrotask()
    • process.nextTick()(Node.js,优先级最高)

流程

当运行一段代码时,先运行同步代码,再清空队列里的当前所有微任务,再进行一个宏任务,再清空队列里的微任务。

同步任务 → 微任务 → 宏任务

以下代码为例

console.log('Start'); // 1

setTimeout(() => {
    console.log('Timeout 1'); // 4
    Promise.resolve().then(() => console.log('Promise in Timeout 1')); // 5
  }, 0);
  
setTimeout(() => {
  console.log('Timeout 2'); // 6
  Promise.resolve().then(() => console.log('Promise in Timeout 2')); // 7
}, 0); 
  
Promise.resolve().then(() => console.log('Promise 1')); // 3

console.log('End'); // 2

  1. 同步代码执行(StartEnd)。
  2. 同步代码执行后处理微任务(Promise 1)。
  3. 执行第一个宏任务(Timeout 1),其微任务立即执行。
  4. 执行第二个宏任务(Timeout 2),同样处理其微任务。

关键点:

  • 微任务优先:每次宏任务结束后,必须清空微任务队列。