vue?3?effect作用與原理解析
Vue 3 的 Effect(副作用) 是整個響應(yīng)式系統(tǒng)的核心機制,負(fù)責(zé)管理依賴追蹤和響應(yīng)式觸發(fā)。理解其作用和原理對掌握 Vue 的底層機制至關(guān)重要。
一、核心作用
1. 依賴追蹤(Dependency Tracking)
- 自動跟蹤響應(yīng)式數(shù)據(jù)在副作用函數(shù)中的使用。
示例代碼:
import { reactive, effect } from 'vue' const obj = reactive({ count: 0 }) effect(() => { console.log(`count is: ${obj.count}`) })
- 當(dāng)首次執(zhí)行
effect
時,函數(shù)() => console.log(...)
會被運行。 - 觸發(fā)
obj.count
的get
操作,觸發(fā)依賴收集(將當(dāng)前effect
關(guān)聯(lián)到obj.count
)。
2. 自動響應(yīng)(Automatic Re-run)
當(dāng)響應(yīng)式數(shù)據(jù)的依賴變化時,自動重新執(zhí)行副作用函數(shù):
obj.count++ // 觸發(fā)依賴更新,控制臺打印 "count is: 1"
3. 支撐高級 API
computed
、watch
、組件渲染函數(shù)等底層都依賴于effect
實現(xiàn)。
二、實現(xiàn)原理
1. 核心類:ReactiveEffect
Vue 3 用 ReactiveEffect
類封裝副作用邏輯,簡化后的源碼結(jié)構(gòu)如下:
class ReactiveEffect<T = any> { // 當(dāng)前 effect 的所有依賴項(其他響應(yīng)式對象) deps: Dep[] = [] // 構(gòu)造函數(shù)參數(shù) constructor( public fn: () => T, // 副作用函數(shù) public scheduler?: () => void // 調(diào)度函數(shù)(控制重新執(zhí)行方式) ) {} // 運行副作用(觸發(fā)依賴收集) run() { activeEffect = this // 標(biāo)記當(dāng)前正在運行的 effect try { return this.fn() } finally { activeEffect = undefined } } // 停止偵聽 stop() { /* 從所有依賴中移除自身 */ } }
2. 依賴收集流程(Track)
數(shù)據(jù)結(jié)構(gòu):
type Dep = Set<ReactiveEffect> // 依賴集合 type TargetMap = WeakMap<Object, Map<string, Dep>> // 全局依賴存儲
- 觸發(fā)時機:響應(yīng)式數(shù)據(jù)的
get
操作觸發(fā)時。 - 流程:
根據(jù)響應(yīng)式對象 (
target
) 和鍵 (key
) 找到存入targetMap
的依賴集合 (dep
)。將當(dāng)前活躍的
activeEffect
添加到dep
中。同時將
dep
加入activeEffect.deps
(反向記錄,用于 cleanup)。
3. 觸發(fā)更新(Trigger)
- 觸發(fā)時機:響應(yīng)式數(shù)據(jù)的
set
操作時。 - 流程:
根據(jù)
target
和key
從targetMap
獲取對應(yīng)的dep
集合。遍歷
dep
中所有effect
:- 如果有
scheduler
(如computed
),執(zhí)行調(diào)度器(優(yōu)化性能)。 - 否則直接執(zhí)行
effect.run()
。
- 如果有
4. 調(diào)度器(Scheduler)
允許控制 effect
如何重新執(zhí)行:
effect(() => { console.log(obj.count) }, { scheduler(effect) { // 如將 effect 推入微任務(wù)隊列中異步執(zhí)行 queueMicrotask(effect.run) } })
- 應(yīng)用場景:
watch
的異步批處理更新。computed
的值懶更新。
三、關(guān)鍵優(yōu)化設(shè)計
1. 嵌套 Effect 棧
用棧結(jié)構(gòu) effectStack
跟蹤嵌套的 effect:
function run() { if (!effectStack.includes(this)) { try { effectStack.push((activeEffect = this)) return this.fn() } finally { effectStack.pop() activeEffect = effectStack[effectStack.length - 1] } } }
- 解決問題:組件嵌套時的依賴關(guān)系混亂。
2. Cleanup 機制
每次 effect 執(zhí)行前清理舊依賴:
function run() { cleanup(this) // 清理之前收集的舊依賴 // ...然后重新收集新依賴 }
- 解決問題:動態(tài)分支邏輯導(dǎo)致的無效依賴(如
v-if
切換導(dǎo)致的條件依賴)。
3. Lazy 執(zhí)行
可配置不立即執(zhí)行 effect:
const runner = effect(fn, { lazy: true }) runner() // 手動執(zhí)行
- 應(yīng)用場景:
computed
屬性初始化時延遲計算。
四、與 Vue 各組件的關(guān)聯(lián)
1. 組件渲染
組件 render
函數(shù)被包裹在 effect
中:
function setupRenderEffect(instance) { effect(() => { const subTree = instance.render.call(instance.proxy) patch(instance.subTree, subTree) instance.subTree = subTree }, { scheduler: queueJob }) // 異步更新隊列 }
2. Computed 實現(xiàn)
computed
通過 effect
+ 調(diào)度器實現(xiàn)懶更新:
const computedRef = new ComputedRefImpl( getter, () => { // 調(diào)度器 if (!this._dirty) { this._dirty = true trigger(this, 'set', 'value') } } )
3. Watch API
watch
基于 effect
的調(diào)度器實現(xiàn)異步回調(diào):
function watch(source, cb, { flush } = {}) { let scheduler if (flush === 'sync') { scheduler = cb } else { // 'post' 或其他默認(rèn)情況 scheduler = () => queuePostFlushCb(cb) } effect(() => traverse(source), { scheduler }) }
五、與 Vue 2 的對比
特性 | Vue 2 (Watcher) | Vue 3 (Effect) |
---|---|---|
依賴追蹤 | 通過遍歷數(shù)據(jù)觸發(fā) getter | 通過 Proxy/Reflect 自動追蹤 |
更新粒度 | 依賴組件級檢查 | 基于精確依賴的靶向更新 |
性能優(yōu)化 | 需手寫 pureComputed 等 | 內(nèi)置自動的依賴清理和調(diào)度機制 |
內(nèi)存管理 | 易產(chǎn)生內(nèi)存泄漏(舊 Dep 引用問題) | 通過 WeakMap 自動釋放無用依賴 |
六、源碼流程圖解
+---------------------+ | Reactive Object | +----------+----------+ │ 訪問屬性時 ▼ +---------------------+ | 觸發(fā) get 代理 +----→ track(target, key) +---------------------+ │ ▲ ▼ 存儲依賴關(guān)系 │ +---------------------+ +----------+ targetMap | | (WeakMap結(jié)構(gòu)) | +---------+-----------+ │ ▼ +---------------------+ | depsMap (Map) | | (key → Dep Set) | +---------+-----------+ │ ▼ +---------------------+ | dep (Set) | | (存儲所有關(guān)聯(lián)的 effect)| +---------------------+
總結(jié)
Vue 3 的 effect
通過以下機制成為響應(yīng)式系統(tǒng)的核心:
- Proxy 依賴收集:精確追蹤響應(yīng)式數(shù)據(jù)的使用。
- 調(diào)度器控制:提供靈活的回調(diào)執(zhí)行方式。
- 內(nèi)存安全:通過
WeakMap
自動管理依賴。 - 框架級優(yōu)化:支持組件渲染、計算屬性、watch 等核心功能。
到此這篇關(guān)于vue 3 effect作用與原理的文章就介紹到這了,更多相關(guān)vue 3 effect作用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue中后端做Excel導(dǎo)出功能返回數(shù)據(jù)流前端的處理操作
這篇文章主要介紹了vue中后端做Excel導(dǎo)出功能返回數(shù)據(jù)流前端的處理操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09element-ui 表格實現(xiàn)單元格可編輯的示例
下面小編就為大家分享一篇element-ui 表格實現(xiàn)單元格可編輯的示例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-02-02