iT邦幫忙

2026 iThome 鐵人賽

DAY 7
0
JavaScript

React 觀念架構:從js 基礎到Hook 底層邏輯 系列 第 7

Day 07 Event Loop 機制:微任務 (Microtask) 與 React 批次更新

  • 分享至 

  • xImage
  •  

我們已經掌握了 Promise 與 Async/Await 的語法。今天我們要探討 JavaScript 底層執行核心——事件循環 (Event Loop)。

了解 Event Loop,能幫住徹底弄懂「程式碼的執行順序」,更能看懂 React 的 Batching(批次更新) 機制是如何與微任務 (Microtask) 巧妙結合的。

一、 JavaScript 的單執行緒與 Event Loop 結構

JavaScript 是單執行緒(Single-threaded)語言,一次只能做一件事。為了處理非同步操作而不卡死畫面,瀏覽器架構了 Event Loop 機制,分為三個核心區域:

  1. Call Stack(呼叫棧):執行同步程式碼的地方,遵守「後進先出 (LIFO)」。

  2. Task Queue / Macrotask Queue(宏任務佇列):存放 setTimeoutsetIntervalDOM 事件I/O 等 Callback

  3. Microtask Queue(微任務佇列):存放 Promise.then/catch/finallyqueueMicrotaskprocess.nextTick 等 Callback。

┌────────────────────────────────────────┐
│              Call Stack                │
└──────────────────┬─────────────────────┘
                   │ Stack 清空時
                   ▼
┌────────────────────────────────────────┐
│           Microtask Queue              │ ◄── 優先清空!(Promise)
└──────────────────┬─────────────────────┘
                   │ 全部清空後
                   ▼
┌────────────────────────────────────────┐
│          Render / Painting             │ ◄── 畫面更新
└──────────────────┬─────────────────────┘
                   │
                   ▼
┌────────────────────────────────────────┐
│           Macrotask Queue              │ ◄── 取出一個執行 (setTimeout)
└────────────────────────────────────────┘

二、 執行優先權比較:Macrotask vs. Microtask

Event Loop 的運作法則:

  1. 同步任務 先在 Call Stack 執行完畢。

  2. 當 Call Stack 清空時,Event Loop 會優先將 Microtask Queue 裡面的任務全部清空。

  3. Microtask 清空後,瀏覽器進行畫面 Rendering(若需要)。

  4. 最後從 Macrotask Queue 取出下一個任務放進 Call Stack 執行。

console.log('1. 同步');

setTimeout(() => {
  console.log('2. Macrotask (setTimeout)');
}, 0);

Promise.resolve().then(() => {
  console.log('3. Microtask (Promise)');
});

console.log('4. 同步');

輸出順序:1. 同步 => 4. 同步 => 3. Microtask (Promise) => 2. Macrotask (setTimeout)

三、 React 18 的 Automatic Batching 與 Microtask

在 React 中,如果你連續呼叫多次 setState,React 不會每呼叫一次就立刻重新渲染一次畫面,而是會將它們「打包批次處理 (Batching)」,只引發一次 Re-render。

React 18 以前的限制

在 React 17 以前,Batching 只在 React 原生事件(如 onClick)中生效。若放在非同步 Callback(如 setTimeout 或 fetch)中,Batching 就會失效:

// React 17:setTimeout 內部呼叫兩次 setState 會觸發兩次 Re-render
setTimeout(() => {
  setCount(c => c + 1); // 觸發 Re-render 1
  setFlag(f => !f);     // 觸發 Re-render 2
}, 1000);

React 18 的全自動批次更新 (Automatic Batching)

React 18 實現了全自動批次更新,不論 State 更新發生在 setTimeout、Promise 還是原生事件中,都會自動打包成一次更新。

而這背後的排程(Scheduler)機制,正是善用了 Event Loop 的 Microtask 階段:

function handleClick() {
  // 1. 同步執行:React 將更新任務收集進內部 Queue,但不立刻渲染
  setCount(c => c + 1);
  setFlag(f => !f);

  // 2. React 透過 queueMicrotask (或 Promise) 註冊一個微任務:
  //    「請在當前同步程式碼執行完畢後,一次性比對並更新 DOM!」
} 
// 3. Call Stack 清空 => 觸發 Microtask => 一次性完成 Batching 與渲染!

上一篇
Day 06 Promise 與 Async/Await:處理非同步資料流的底層觀念
系列文
React 觀念架構:從js 基礎到Hook 底層邏輯 7
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言