Watch 和 Computed 誰比較快執行?
最近朋友在面試時被問到這個問題,超有趣的!我想來好好研究一下 Vue 源碼中 Watch 和 Computed 的差異,看看到底誰比較快!
先搞懂 Vue 的響應式系統
在深入比較之前,我們得先知道 Vue 的響應式是怎麼回事。簡單說,Vue3 用 Proxy 來監聽數據變化,當數據更新時頁面也會跟著更新。
Proxy 基本上就是幫 Vue 攔截對象的讀取(get)和修改(set)操作。來看看官網的簡易實現:
這裡有兩個關鍵概念,它們是理解 Watch 和 Computed 的基礎:
- track: 記錄「誰」依賴於這個屬性(比如組件渲染函數或計算屬性)
- trigger: 當屬性變化時,通知所有依賴者更新
看看真實源碼中的實現,你會發現同樣的 track 和 trigger 機制:
理解了響應式系統後,我們就能更深入地理解 Watch 和 Computed 了!
Watch 是什麼?
簡單來說,Watch 就是一個「跟蹤者」。你告訴它要盯著哪個數據,當數據變化時,它會執行你給的回調函數。
Watch 的特點:
- 明確追蹤特定數據源(可以是 ref、響應式對象或函數)
- 數據變化時執行回調,通常會給你新值和舊值
- 適合執行「副作用」,比如異步操作或複雜邏輯
來看看 Vue 源碼是如何實現 Watch 的:
從源碼可以看出,Watch 的核心就是創建一個 ReactiveEffect 實例,當依賴變化時,它會執行你提供的回調函數。這就是為什麼 Watch 適合處理「副作用」——它的設計初衷就是在數據變化時執行操作,而不是計算新值。
Computed 是什麼?
Computed 則是基於現有數據「計算」出新的數據。它像是一個聰明的助手,會記住計算結果直到依賴的數據變化。
Computed 的特點:
- 基於現有響應式數據計算新值
- 有緩存機制,避免重複計算
- 適合簡單操作,讓模板更乾淨
來看看 Computed 在源碼中的關鍵實現:
從源碼可以清楚看到 Computed 的兩個核心特性:
- 當依賴變化時,只是標記為「髒」(
EffectFlags.DIRTY
),不立即重新計算 - 只有當真正需要值時(有人讀取
.value
),才會根據「髒」標記決定是否重新計算
這就是 Computed 高效的秘密——懶計算加緩存機制,避免不必要的重複計算,特別適合那些計算結果會被多次使用的場景。
Watch vs Computed:詳細比較
既然我們已經看過源碼實現了,讓我們來總結一下 Watch 和 Computed 的核心差異:
特性 | Computed | Watch |
---|---|---|
目的 | 計算新數據 | 執行副作用 |
返回值 | 有返回值 | 沒有返回值 |
緩存 | 有緩存機制 | 每次都執行 |
計算時機 | 用到才計算(懶評估) | 數據變化就執行 |
副作用 | 不適合(反模式) | 設計來做這個的 |
異步操作 | 不適合 | 完全適合 |
程式風格 | 宣告式 | 命令式 |
性能考量 | 自動高效(緩存) | 開發者需自行優化 |
這些差異直接反映了它們在源碼中的實現方式:Computed 專注於有效率地產生和緩存值,而 Watch 則專注於在正確時機執行回調。
實際應用指南
基於源碼分析,這裡有一些實用的指導原則:
什麼時候用 Computed:
- 需要從其他數據計算出新數據時
- 計算結果會被多次使用時(利用緩存提高性能)
- 想讓模板更簡潔,把複雜邏輯移出來時
- 需要在多處使用相同計算邏輯時
什麼時候用 Watch:
- 需要在數據變化時調用 API
- 執行有「副作用」的操作時
- 需要實現防抖或節流時(watch 支持
deep
和immediate
等選項) - 需要比較數據變化前後的值時(watch 回調提供新舊值)
- 需要監聽多個數據源並在任何一個變化時執行操作
誰比較快?源碼給出的答案
回到我們最初的問題:在源碼層面,Computed 通常會更快執行。為什麼呢?讓我們從源碼中找出答案:
- Computed 有緩存機制:從源碼中可以看到,Computed 使用
refreshComputed(this)
來判斷是否需要重新計算。只有當:- 依賴的數據變化了(標記為「髒」)
- 確實有人訪問這個計算屬性 才會重新計算
- Watch 沒有緩存:Watch 的回調在每次依賴變化時都會執行,沒有跳過的機制(除非你自己實現)
但實際上,兩者的速度取決於你的應用場景:
- 對於需要多次訪問的計算結果,Computed 肯定更快(得益於其緩存機制)
- 對於異步操作或複雜副作用,Watch 更合適(雖然不一定更快)
源碼揭示的最佳實踐
從 Vue 的源碼設計中,我們可以學到一個很重要的原則:先考慮用 Computed(聲明式),只有在真正需要副作用或異步操作時才用 Watch(命令式)。
這不僅符合 Vue 的設計理念,也能讓你的應用獲得更好的性能和可維護性。Vue 源碼中 Computed 精心設計的緩存機制不僅能提高性能,還能「阻止不必要的下游更新」,這在複雜應用中尤為重要。
選對工具,讓你的 Vue 應用更高效!