vue实现依赖收集
Vue 依赖收集实现原理
Vue 的依赖收集机制基于响应式系统,核心是通过 Object.defineProperty 或 Proxy 拦截数据访问,在 getter 中收集依赖,在 setter 中触发更新。
核心实现步骤
初始化阶段
- 通过
Observer类将数据对象转换为响应式对象,遍历对象的每个属性,使用Object.defineProperty定义 getter/setter。 - 每个响应式属性会关联一个
Dep实例(依赖收集器),用于存储所有依赖该属性的Watcher。
依赖收集过程
- 当组件渲染或计算属性计算时,会创建一个
Watcher实例。 Watcher在求值前会调用pushTarget方法,将自身设置为当前活跃的Watcher。- 访问响应式数据时触发 getter,getter 中调用
dep.depend(),将当前活跃的Watcher添加到Dep的订阅列表中。 - 完成求值后,
Watcher通过popTarget移除当前活跃状态。
派发更新过程
- 修改响应式数据时触发 setter,调用
dep.notify()通知所有订阅的Watcher更新。 Watcher更新可能触发重新渲染或重新计算,形成闭环。
关键代码示例
// 简化版 Observer 实现
class Observer {
constructor(value) {
this.value = value
this.walk(value)
}
walk(obj) {
Object.keys(obj).forEach(key => {
defineReactive(obj, key, obj[key])
})
}
}
function defineReactive(obj, key, val) {
const dep = new Dep()
Object.defineProperty(obj, key, {
get() {
if (Dep.target) {
dep.depend()
}
return val
},
set(newVal) {
if (newVal === val) return
val = newVal
dep.notify()
}
})
}
// Dep 实现
class Dep {
constructor() {
this.subs = []
}
depend() {
if (Dep.target) {
Dep.target.addDep(this)
}
}
notify() {
this.subs.forEach(watcher => watcher.update())
}
}
// Watcher 实现
class Watcher {
constructor(getter) {
this.getter = getter
this.get()
}
get() {
pushTarget(this)
this.value = this.getter()
popTarget()
return this.value
}
update() {
this.get()
}
}
现代 Vue 3 的改进
Vue 3 使用 Proxy 替代 Object.defineProperty,解决了以下问题:
- 可检测数组索引修改和 length 变化
- 支持动态添加新属性
- 性能更好
依赖收集原理类似,但实现更简洁:
const reactive = (target) => {
return new Proxy(target, {
get(target, key, receiver) {
track(target, key)
return Reflect.get(target, key, receiver)
},
set(target, key, value, receiver) {
Reflect.set(target, key, value, receiver)
trigger(target, key)
}
})
}
性能优化策略
- 组件级依赖收集:每个组件对应一个渲染
Watcher,减少不必要的更新 - 异步更新队列:多次数据变化合并为一次更新
- 计算属性缓存:依赖不变时直接返回缓存值
v-once指令:标记静态内容避免重复渲染







