「这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战」
数据响应式原理-依赖收集
依赖收集其实就是把依赖该属性的watcher对象添加到 dep 对象的 subs 数组中,当依赖数据发生变化的时候通知所有的watcher
何时收集依赖?
何时收集依赖,这个时候我们需要进行一些逆向思维,什么时候需要使这个数据及时更新?
- 这个数据被视图层使用的时候
那么这样就很简单了,我们就可以在读取的时候进行对应的依赖收集,也就是
Object.defineProperty的get的时候
get: function reactiveGetter () {
// 如果预定义的 getter 存在则 value 等于getter 调用的返回值
// 否则直接赋予属性值
const value = getter ? getter.call(obj) : val
// 如果存在当前依赖目标,即 watcher 对象,则建立依赖
if (Dep.target) {
dep.depend()
// 如果子观察目标存在,建立子对象的依赖关系
if (childOb) {
childOb.dep.depend()
// 如果属性是数组,则特殊处理收集数组对象依赖
if (Array.isArray(value)) {
dependArray(value)
}
}
}
// 返回属性值
return value
}
Dep.target 属性何时初始化?
之前我们进行模拟的时候也有提到 模拟,Dep.targe就是在我们创建 watcher 类的时候进行初始化的
那我们先查看
watcher类:- 路径:
src\core\observer\watcher.js我们可以看见 构造函数中
vm._watchers.push(this)
将 watcher 对象 存储到了vue的 _watchers数组中
接着,我们还可以看见这样一段代码:
this.value = this.lazy
? undefined
: this.get()
重头戏来了
- get 方法: 这里我们调用了 pushTarget 方法并且将 watcher 实例传入
get () {
pushTarget(this)
...
}
- pushTarget: 这里为 Dep.target = target, 并且值就是我们的 watcher 对象
Dep.target = null
const targetStack = []
// 入栈并将当前 watcher 赋值给 Dep.target
// 父子组件嵌套的时候先把父组件对应的 watcher 入栈,
// 再去处理子组件的 watcher,子组件的处理完毕后,再把父组件对应的 watcher 出栈,继续操作
export function pushTarget (target: ?Watcher) {
targetStack.push(target)
Dep.target = target
}
Dep.target 用来存放目前正在使用的watcher 全局唯一,并且一次也只能有一个watcher被使用
dep.depend() 收集依赖
// 将观察对象和 watcher 建立依赖
depend () {
if (Dep.target) {
// 如果 target 存在,把 dep 对象添加到 watcher 的依赖中
Dep.target.addDep(this)
}
}
这里我们可以看见我们调用了 Dep.target.addDep(this),加上我们上面的了解target就是watcher,所以我们要了解addDep就有需要回到watcher类中了
addDep
路径: src\core\observer\watcher.js
addDep (dep: Dep) {
const id = dep.id
// 判断当前是否存储了 这个对象
if (!this.newDepIds.has(id)) {
// 如果没有的话 将数据存储到 watcher 的集合中
this.newDepIds.add(id)
this.newDeps.push(dep)
// 最后会把 watcher 这个对象 添加到 dep的subs数组中
if (!this.depIds.has(id)) {
dep.addSub(this)
}
}
}
这个方法很简单,首先 判断当前是否存储了这个对象,如果没有的话 将数据存储到 watcher 的集合中,最后会把 watcher 这个对象 添加到 dep的subs数组中
总结
- 在
watcher的get方法中,会给Dep.target进行赋值操作 - 在
Dep.target存在之后,我们会调用dep.depend()这个方法,这个方法最终是要把 watcher 这个对象 添加到 dep的subs数组中