跳至主要内容

課程:JavaScript 與 React 底層原理 第 15 堂:Lane 模型基礎

Lesson 15 note

本課深入探討 React Lane 模型的設計初衷,從優先級調度的必要性出發,解析底層 Bitmask 位元運算機制,並詳解各類 Lane 在真實開發場景中的應用。透過理解這些機制,我們能掌握 React 如何在資源有限的情況下,確保 UI 互動的極致流暢。

優先級調度的動機

  • 僅有中斷機制是不夠的:Fiber 架構雖然賦予 React 暫停工作的能力,但當瀏覽器將控制權還給 React 時,需要「插隊機制」來決定下一個該執行的任務,否則過時的長任務仍會阻塞緊急的更新。
  • 16.6ms 幀預算與感知門檻:人類對不同互動有不同容忍度。點擊與打字(離散事件)需在 100ms 內反應,而捲動與拖曳(連續事件)則需維持在 60 FPS,優先級調度即是將資源優先分配給最影響使用者感知的任務。
  • 從「火車」到「航空調度」:類比 React 演進,從不可中斷的同步渲染,進化到可中斷的區間車,最後到 Lane 模型這種能根據任務類別(醫療專機 vs 貨機)彈性調配跑道的智慧系統。

Lane 的位元表示法

  • 從 ExpirationTime 到 Lane 的演進:舊有的過期時間模型難以表示「一組」任務,Lane 模型則透過 32 位元整數(Bitmask)將每一位元視為一條獨立「賽道」,實現多賽道同時管理。
  • 位元運算的 O(1) 效能優勢:
    • 合併賽道(OR |):將多個更新標記合併至待處理清單。
  • 檢查包含(AND &):極速判斷目前任務中是否包含特定優先級。
  • 移除賽道(AND + NOT & ~):任務完成後精準剔除該位元,不影響其他待處理任務。
  • 記憶體與 GC 效率:位元運算屬於底層 CPU 指令且不產生額外物件,避免了使用陣列或物件帶來的記憶體佔用與垃圾回收(GC)壓力。

Lane 的分類與情境

  • SyncLane(最高優先級):對應 flushSync,用於同步且不可中斷的更新。雖能立即反映,但會阻塞主執行緒,過度使用會導致 UI 卡頓。
  • InputContinuousLane:專用於連續輸入事件如 onScrollonDrag,確保動畫與視覺反饋的平滑。
  • DefaultLane:最常見的賽道,處理一般的 setState 與資料請求後的更新,支持自動批次處理(Automatic Batching)。
  • TransitionLane(核心黑科技):由 startTransition 標記,代表不影響即時反饋的重量級變更。其優先級極低且「可被插隊並丟棄」,是 Concurrent Mode 解決卡頓的關鍵。
  • IdleLane(最低優先級):僅在系統完全閒置時執行,適用於預取資料或日誌統計。

Q&A

  • Q: 在開發搜尋功能時,如何運用 Lane 確保打字不卡頓?
    • 將「輸入框文字更新」保持在預設優先級,而將「搜尋結果清單更新」標記為 TransitionLane
  • 這樣當 React 正在渲染耗時的搜尋結果時,新的打字更新(較高等級)可以直接中斷目前的渲染,實現「救護車插隊」的效果,維持 UI 的即時反應。
  • Q: 為什麼移除已完成的 Lane 必須使用 & ~ 而不能直接用 &
    • ~(NOT)運算子能建立一個「除了目標賽道外,其餘全開」的過濾網。
  • 若誤用 pendingLanes & lastProcessedLanes,會導致 AND 特性將除了目標外的所有待處理任務全部抹消,造成背景任務突然消失的嚴重 Bug。
  • Q: 過度使用 SyncLane(如頻繁呼叫 flushSync)會有什麼後果?
    • 會破壞 Fiber 架構的「可中斷性」。
  • React 會被迫一次執行到底直到完成,就像消防車出動時所有車輛必須停下,這會讓應用重回 React 15 那種一旦開始渲染就無法回應任何使用者互動的卡頓狀態。