Vue3系列 - 依赖收集与更新机制
依赖收集与更新机制
Vue的响应式系统核心在于依赖收集和更新通知机制,这是通过Dep类实现的。让我们深入了解Vue2.7中的依赖收集与更新机制。
Dep类的作用
Dep类是Vue响应式系统的核心,它负责:
- 收集依赖(订阅者,通常是Watcher实例)
- 在数据变化时通知这些依赖更新
在Vue2.7中,Dep类的使用可以在customRef
的实现中看到:
export function customRef(factory) {
const dep = new Dep()
const { get, set } = factory(
() => {
if (__DEV__) {
dep.depend({
target: ref,
type: TrackOpTypes.GET,
key: 'value'
})
} else {
dep.depend()
}
},
() => {
if (__DEV__) {
dep.notify({
target: ref,
type: TriggerOpTypes.SET,
key: 'value'
})
} else {
dep.notify()
}
}
)
// ...
}
依赖收集过程
依赖收集发生在数据被访问(getter)时:
- 当组件渲染或计算属性计算时,会创建一个Watcher实例
- Watcher将自己设置为当前的依赖收集目标(通过
pushTarget
) - 访问响应式数据的getter时,调用
dep.depend()
将当前Watcher添加到依赖列表 - 渲染或计算完成后,恢复之前的依赖收集目标(通过
popTarget
)
更新通知过程
更新通知发生在数据被修改(setter)时:
- 当响应式数据的值被修改时,触发setter
- setter调用
dep.notify()
通知所有依赖 - 每个Watcher接收到通知后,根据自己的配置决定如何更新(同步或异步)
- 对于渲染Watcher,最终会调用组件的重新渲染
在setup中的依赖收集
在setup
函数执行过程中,Vue也使用了依赖收集机制:
export function initSetup(vm) {
// ...
if (setup) {
// ...
setCurrentInstance(vm)
pushTarget() // 设置依赖收集目标
const setupResult = invokeWithErrorHandling(
setup,
null,
[vm._props || shallowReactive({}), ctx],
vm,
`setup`
)
popTarget() // 恢复之前的依赖收集目标
setCurrentInstance()
// ...
}
}
这确保了在setup
函数中访问的响应式数据能够正确地收集依赖。
调试依赖关系
Vue3引入了onRenderTracked
和onRenderTriggered
钩子,帮助开发者调试依赖关系:
const Comp = {
setup() {
onRenderTracked((event) => {
console.log('依赖被追踪', event)
})
onRenderTriggered((event) => {
console.log('更新被触发', event)
})
// ...
}
}
总结
依赖收集与更新机制是Vue响应式系统的核心。通过Dep类,Vue实现了数据与使用数据的地方(如组件渲染、计算属性)之间的连接。理解这一机制,有助于我们更好地理解Vue的响应式原理,解决响应式相关的问题,并编写更高效的Vue应用。