iT邦幫忙

2025 iThome 鐵人賽

DAY 27
0

前情提要

在前一篇,我們探討了 Scheduler 與圖 (Graph) 的關係,並處理了記憶體與依賴管理的挑戰。
但在真實應用中,任務並不都是「同等級」的:

  • 有些更新必須 立即生效(例如使用者輸入的文字)
  • 有些更新則可以 延遲處理(例如動畫、低優先 UI)

這時就需要 優先級 (Priority)分層 Scheduler 的設計。

為什麼需要優先級?

想像這個場景,使用者正在輸入文字 (input.onChange),同時後台有一個大型計算任務(例如 chart re-render)。

如果兩者都放進同一個 queue,且無優先級控制,使用者輸入就可能被「卡住」,造成體驗不佳。

解法:讓 高優先級任務(輸入事件) 先處理,低優先級任務延後執行。

優先級的常見分類

在現代前端框架中,通常會有類似以下的分級:

  • Immediate / Sync
    • 例如輸入框的文字更新、緊急錯誤提示
    • 必須立刻反應,不能被延遲
  • High Priority
    • UI 主流程,例如按鈕點擊觸發的狀態變更
  • Normal Priority
    • 大部分非關鍵的 UI 更新
  • Low Priority / Idle
    • 背景計算、效能統計、預取 (prefetch)

這樣可以確保:體驗最關鍵的互動永遠先執行。

分層 Scheduler (Layered Scheduling)

除了優先級,另一個重要概念是「分層」。

我們可以將任務劃分成不同 層級 (layers),讓每個層都有獨立的 queue,並用 Scheduler 來協調:

  • 計算層 (Computation Layer)
    • Signal / Computed 更新
  • UI 層 (UI Layer)
    • DOM 更新、Virtual DOM diff
  • I/O 層 (I/O Layer)
    • fetch、網路請求、storage
  • Idle 層 (Idle Layer)
    • 非必要的背景任務,例如 log 收集

這種劃分方式有點像作業系統的 CPU Scheduler:不同類型的任務分開管理,避免互相干擾。

程式架構範例

以下是一個簡化版的「分層 + 優先級」 Scheduler:

type Priority = "immediate" | "high" | "normal" | "low";

interface Job {
  run(): void;
  priority: Priority;
  layer: "compute" | "ui" | "io" | "idle";
}

const queues: Record<Priority, Job[]> = {
  immediate: [],
  high: [],
  normal: [],
  low: [],
};

export function scheduleJob(job: Job) {
  queues[job.priority].push(job);
  requestFlush();
}

function requestFlush() {
  queueMicrotask(flushJobs);
}

function flushJobs() {
  // 按優先級執行
  runQueue(queues.immediate);
  runQueue(queues.high);
  runQueue(queues.normal);
  runQueue(queues.low);
}

function runQueue(queue: Job[]) {
  while (queue.length > 0) {
    const job = queue.shift()!;
    job.run();
  }
}

這是一個「單層優先級」範例,若要進一步分層,可以在 Job.layer 上再細分不同的 queue。

透過圖表了解這段執行的任務

https://ithelp.ithome.com.tw/upload/images/20250829/20129020Ii0HOwZBdo.png

效能與最佳化策略

  • 批次處理 (Batching)
    • 同一優先級的任務可以合併,避免重複計算。
  • 時間切片 (Time-Slicing)
    • 在長任務中,允許切分成小片段執行,避免主執行緒卡死。
    • React Concurrent Mode 就使用了這種策略。
  • 瀑布式執行 (Waterfall Execution)
    • 先跑完高優先級 → 若時間允許再處理低優先級。
    • 若時間不足,低優先級任務可延遲到下一個 tick。

結語

從單一 queue 到「優先級 + 分層」的 Scheduler,最大的目標就是:

在確保互動即時性的同時,最大化效能利用率。

這也是為什麼 React 引入 Concurrent Features、Vue 使用 job queue,而 Signal-based 系統也開始設計更細緻的 Scheduler。

下一篇,我們會更深入探討「Time-Slicing 與協作式排程 (Cooperative Scheduling)」,讓 scheduler 能在繁重任務中保持流暢的互動體驗。


上一篇
進階內核(IV):記憶體與圖管理
系列文
Reactivity 小技巧大變革:掌握 Signals 就這麼簡單!27
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言