2010 年的 Knockout.js 首度將 Observable
/ Computed
帶進前端,讓「資料自己開口,UI 跟着動」成為可行路徑。-> Knockout介紹
此後,前端的發展圍繞「到底是資料主動通知,還是框架主動打聽?」展開十多年的試驗。
從事後諸葛的角度來看,Knockout 確實是造成後來三強鼎立 (Angular, React, Vue) 的幕後推手,主要是思想層面上帶來的啟發,才激起後續不同解決方案的框架核心。
本文聚焦 UI 的 reactivity(與 FRP/Reactive Programming 有關聯、但不等同),並說明它如何影響之後的 Angular/React/Vue 以及 Signals 等技術走向。
讓「資料 → UI」的同步,從手動改 DOM,變成資料自己驅動畫面。
誰先開口? | 策略 | 典型做法 | 關鍵詞 |
---|---|---|---|
框架主動詢問 | Pull | 迴圈比對/VDOM diff | dirty-checking , diff |
資料主動通知 | Push | watcher/signal | observable , effect |
多數現代框架其實是 Hybrid:由資料端 push 失效、在收斂時機 pull 需要的計算或 diff。
先快速對照,之後再細看每種做法如何平衡效能與心智負擔。
模型 | 極簡更新流程 | Push / Pull 落點 | 粒度 & 備註 | 代表框架 |
---|---|---|---|---|
Dirty-checking | $digest 逐一比對所有 $watch → 差異即時同步 |
純 Pull:框架主動「掃資料」 | 元件/表達式層級;效能隨監聽數量線性衰減 | AngularJS 1.x (ryanclark.me) |
Virtual-DOM diff | setState Push 髒標記 → 批次 re-render → VDOM Pull diff → DOM patch |
Hybrid:Push 觸發+Pull 收斂 | 以「子樹」為單位;心智簡單但可能產生過度 render | React, Preact, Vue 2 (Medium) |
Watcher / Observable Graph | setter Push 通知相關 Watcher → Watcher 只重算自己子樹 | 偏 Push | 依賴由「getter 時自動追蹤」建立;粒度比 B 更細 | Vue 2 Watcher, MobX (Vue.js) |
Fine-grained Signals | setter Push 失效 → 被讀取時 Pull 重算(lazy)→ 直接 patch DOM | Runtime:Hybrid:Push 失效+Pull 計算;Compile-time:近純 Push | 屬性/DOM 節點級;圖最細、無 VDOM | Runtime:Solid.js, Angular Signals (DEV Community)|Compile-time:Svelte 5 Runes(Scalable Path) |
對應上表更新流程
對應上表更新流程
對應上表更新流程
對應上表更新流程
batch
/ microtask
,在同一 tick 合併多次修改。job-queue
方式分批。Reactivity 的進化是一條不斷調和「推」與「拉」的歷史。
到這裡,你已掌握了四大模型在「誰先開口、開口後影響多大」上的差異。
但還有一個關鍵問題尚未揭開:即使在最細顆粒度的系統裡,為什麼仍需要「Pull」?
下一篇,讓我們來詳細理解,什麼是 Pull-based & Push-based?