跳至主要內容
Skip to content

JS 實戰 (5) —— Signals:現代響應式之巔與細粒度更新

在系列文章的第一篇中,我們學會了如何用 get / set 實現響應式。隨著技術演進,現代前端界出現了一個橫掃所有主流框架的新寵兒:Signals

從 Solid.js 的崛起,到 Preact 的引入,再到 Vue 3.4 的底層重構與 Angular 17+ 的全面擁抱——我們正處於「Signals 時代」。


一、 什麼是 Signal?

簡單來說,Signal 是一個同時具備「值」與「通知能力」的容器

1. 語法初探

在多數庫中,它的長相像這樣:

javascript
// 偽代碼
const count = signal(0);

// 讀取:它是一個函式,或者透過 .value 觸發 Getter
console.log(count());

// 寫入:透過函式呼叫或 Setter
count.set(count() + 1);

二、 為什麼需要 Signals?(vs Virtual DOM)

React 引領了 Virtual DOM 的時代:只要資料變了,我就重新執行整個元件函式,產生一棵新的虛擬樹,然後進行比對 (Diffing)。

Signals 的哲學完全不同:細粒度 (Fine-grained)。

  1. 直達末梢:當 count 改變時,Signal 知道到底在哪個 HTML 標籤裡讀取了它。
  2. 無需 Diff:它不需要重新執行整個元件,也不需要比對整棵樹,它可以精準地只更新那個變動的文本節點或屬性。

三、 底層機制:Getter 的終極應用

Signals 的魔法關鍵在於:自動依賴追蹤。而這正是利用了我們學過的 Getter 機制。

javascript
// 一個極簡版的 Signal 實現
let activeEffect = null;

function signal(initialValue) {
  let _val = initialValue;
  const subscribers = new Set();

  return {
    get value() {
      // 核心:誰在讀取我?我就把誰存起來 (依賴收集)
      if (activeEffect) subscribers.add(activeEffect);
      return _val;
    },
    set value(newVal) {
      if (_val === newVal) return;
      _val = newVal;
      // 核心:資料變了,通知所有人執行 (派發更新)
      subscribers.forEach((fn) => fn());
    },
  };
}

function effect(fn) {
  activeEffect = fn;
  fn(); // 第一次執行,觸發內部 Signal 的 Getter
  activeEffect = null;
}

四、 Signal 與傳統 Ref/Reactive 的區別

在 Vue 3 中,refsignal 其實非常接近,但 Signals 通常具備以下進階特性:

  • 延遲執行 (Lazy Execution):只有在屬性真正需要被讀取時,才會進行計算。
  • 無縫組合 (Composability):你可以輕鬆地把多個 Signals 組合成一個 computed Signal。
  • 框架無關:現在的 Signals 規範正朝向標準化邁進,許多庫甚至可以脫離 UI 框架獨立運行。

五、 實戰場景:什麼時候該用?

  • 高頻更新:例如股票報價圖表、大型複雜表格,不適合 Virtual DOM 全量比對的場景。
  • 超輕量組件:像 Solid.js 這種追求零開銷 (Zero-overhead) 的原生開發體驗。
  • 跨組件狀態同步:Signals 天生就適合在不同的元件樹分支間同步狀態。

總結

JavaScript 的演進始終圍繞著「如何更有效率地處理狀態變動」。從基礎的物件屬性,到 defineProperty 的劫持,再到 Proxy 的代理,最後演變成了 Signals 這種細粒度的原語。

理解了 Accessors,你就理解了這一切的根基。


️ 進階挑戰

  1. 實作挑戰:試著用上面的 signal 程式碼實作一個 computed(fn)。它應該能在依賴的 Signal 變動時,自動重新計算結果。
  2. 深度思考:如果 Signals 這麼好,為什麼 React 官方至今仍不考慮官方支援 Signals?(提示:React 的純函式渲染模型與 Signals 的可變/依賴收集模型有什麼衝突?)。

延伸閱讀與資源

返回專題首頁