iT邦幫忙

2025 iThome 鐵人賽

DAY 28
0
Modern Web

Reactivity 小技巧大變革:掌握 Signals 就這麼簡單!系列 第 28

進階內核(VI):Time-Slicing 與協作式排程

  • 分享至 

  • xImage
  •  

前情提要

在前一篇,我們介紹了 優先級與分層 Scheduler,解決了「重要任務先跑」的問題。
然而,在實際應用中,我們還會遇到另一個挑戰:長任務會阻塞主執行緒

為了讓使用者始終感覺流暢,Scheduler 必須支援 Time-Slicing (時間切片) 與 Cooperative Scheduling (協作式排程)。

問題:長任務阻塞

想像一個場景:
UI thread 正在執行一個 大型渲染任務(例如一次更新 5000 筆列表項目),這段程式可能需要數十毫秒,甚至超過 100ms 才能完成。

在這段時間內:

  • 使用者滑鼠移動 / 鍵盤輸入 → 無法即時回應
  • 畫面可能卡住,掉到 < 60 FPS,造成明顯卡頓

光靠「優先級」不夠,因為任務一旦進入執行階段,仍然可能「獨佔主執行緒」。

Time-Slicing (時間切片)

Time-Slicing 的核心思想是:

將一個長任務切分成小片段,允許在片段之間釋放主執行緒。

流程

  1. 任務被拆成多個小步驟 (chunks)
  2. 每執行一小段,就檢查 是否還有剩餘時間
  3. 如果沒有 → 暫停,等待下一個空閒時間再繼續

這樣可以確保:

  • 使用者輸入 / 動畫更新 仍能即時響應
  • 背景任務則「漸進式」完成

Cooperative Scheduling (協作式排程)

在作業系統裡,有 Preemptive Scheduling (搶佔式)Cooperative Scheduling (協作式)
JavaScript 單執行緒的世界裡,沒有辦法真正「搶佔」。

所以框架會採取協作式排程:

  • 任務必須「自願」檢查是否應該中斷 (shouldYield())
  • 中斷後 → 把剩下的工作重新排進 queue

這就是 React Concurrent Mode 採用的策略。

實作範例

這是一個簡化的「時間切片 + 協作式」 Scheduler:

let deadline = 0;

function shouldYield() {
  return performance.now() >= deadline;
}

export function runWithTimeSlicing<T>(work: () => T, timeSlice = 5): T | void {
  deadline = performance.now() + timeSlice;

  while (!shouldYield()) {
    const result = work();
    return result;
  }

  // 沒做完 → 延後執行
  queueMicrotask(() => runWithTimeSlicing(work, timeSlice));
}
  • 每次只允許執行 timeSlice 毫秒,超過就交還控制權。
  • 這樣可以避免「長任務佔據主執行緒」。

與優先級結合

在 分層 + 優先級 Scheduler 的基礎上,我們還能結合 Time-Slicing:

  • Immediate / High Priority → 不切片,直接執行
  • Normal Priority → 使用時間切片,逐步完成
  • Low / Idle Priority → 依賴 requestIdleCallback,只在瀏覽器空閒時處理

這樣就能兼顧即時互動背景大任務整體流暢度

時間切片排程

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

結語

優先級 解決了「先處理誰」的問題,
Time-Slicing 與協作式排程 則解決了「如何避免卡頓」的問題。

這兩者結合,讓 Signal 系統或 React/Vue 這類框架,能在面對 龐大更新量 時仍保持流暢。

下一篇,我們會探討「DevTools 與診斷」包括 inspect 節點、依賴圖可視化、render 計數器、熱點追蹤等工具,如何幫助我們理解 signal 與 scheduler 在真實應用中的行為。


上一篇
進階內核(V):優先級與分層 Scheduler
系列文
Reactivity 小技巧大變革:掌握 Signals 就這麼簡單!28
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言