一開始建立 Composition API 概念中提到,Vue 3.5 的響應式是 Proxy 管家統包;經過漫漫歲月,凡事講求效率,於是 Vue 3.6 新世代響應式的關鍵技術轉變成 Alien Signals。
Vue 3.6 帶來的 Vapor Mode 只是表面現象,真正支撐效能飛躍的,其實是內部重新設計的響應式追蹤系統:Alien Signals。
今天,我們就來拆解這個名字聽起來陌生、但實際上非常工程化的核心技術,看看它為什麼能比 Proxy 更快,並且對我們的開發方式帶來哪些影響。
在 Vue 3.0 ~ 3.5 之前,響應式系統主要依賴 ES6 Proxy:
const state = reactive({ count: 0 })
watchEffect(() => {
console.log(state.count) // 讀取時收集依賴
})
state.count++ // 觸發 setter,通知更新
優點:透過 Proxy 攔截 get / set,可監控物件內任意屬性。
缺點:
隨著前端應用愈來愈大,這種做法在極端場景(例如:成千上萬個 composable、百萬筆資料表格)就會成為瓶頸。
Alien Signals 的設計靈感來自 SolidJS 的 fine-grained reactivity,但更符合 Vue 的模板編譯邏輯:
特徵 | Proxy (舊) | Alien Signals (新) |
---|---|---|
依賴單位 | 整個物件 | 單一 signal (細到變數層級) |
收集時機 | 執行期攔截 | 編譯期生成 |
變更觸發 | setter | signal.set() |
目標 | 通用 | 極致效能 (Vapor Mode) |
Signal
是一個包裹單一值的「資料單元」:
import { signal, effect } from 'vue'
const count = signal(0)
effect(() => {
console.log(count.value) // 訂閱
})
count.value++ // 僅通知使用到 count 的 effect
關鍵差異:
無 Proxy:直接讀寫.value
,不必攔截整個物件。
靜態依賴圖:Vapor 編譯時就能知道哪些模板節點依賴哪些 signal。
更新極快:修改 signal 只會更新直接依賴的模板,跳過無關節點。
當我們啟用 vapor: true
編譯 SFC:
<template vapor>
<div>{{ count }}</div>
</template>
Vapor 會將 {{ count }}
直接編譯成:
const count = signal(0)
const vnode = createVNode("div")
effect(() => vnode.text = count.value)
沒有 Proxy、沒有 reactive() 包裝,甚至連 render() 都不需要呼叫多次。
這就是為什麼在大量 DOM 更新場景下,Vapor + Alien Signals 能帶來數倍效能提升。
Vue 3.6 在 vue 套件中提供實驗性 API:
import { signal, computed, effect } from 'vue'
// 建立 signal
const count = signal(0)
// 建立 computed signal
const double = computed(() => count.value * 2)
// 副作用
effect(() => console.log(double.value))
signal(initial)
:建立可寫的 signal。computed(fn)
:基於 signal 計算衍生值。effect(fn)
:響應副作用,類似 watchEffect。
注意:目前這些 API 主要在 Vapor Mode 中使用,正式應用仍以
ref
/reactive
為主。
還記得昨天的萬次計數器嗎?
實作方式 | 更新平均耗時 (ms) | 記憶體佔用 (MB) |
---|---|---|
reactive + watchEffect | -25.8 | -142 |
signal + effect (Vapor) | -7.1 | -68 |
結果顯示:
數據來自本地 Vite + Vue 3.6-beta 測試,硬體:M1 Pro
從上面的資訊得知,對於我們開發來說在寫法不用刻意調整的條件下,還能夠擁有高效成品,這樣的背後意義包含:
Alien Signals 的出現,代表 Vue 正式進入 fine-grained reactivity 時代:
「從物件到變數」的轉變,讓每一次渲染都只針對最小單位進行更新。