-
需要一个数据对象: data,他需要被处理响应: observe(data, true /* asRootData */)
-
observe 做了啥?(数组的先放一边)
- 通过new Observer(value) 进行处理,他有一个管家Dep,同时有个小工this.walk(value)
// 小工开始干活
walk (obj: Object) {
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i])
}
}
-
defineReactive做了啥? 为每个对象的key 分配一个管家dep,并监听对象的get 和 set行为。再set的时候,通过dep发出更新通知,get的时候,收集需要通知的对象(依赖收集)
-
如何依赖收集?
在对象的Set方法中看到如下代码:
get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val
**// 这个判断是啥鬼东西?**
if (Dep.target) {
**// 这行代码又是啥?**
dep.depend()
// 子ob也要和当前watcher建立关系
if (childOb) {
childOb.dep.depend()
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
}
- 看源码从而得到的答案:
Dep.target是管家类的定义对象,默认为null
depend() 方法是 是管家的方法
那需要了解Dep.target何时赋值?其次depend()做了,我们基本就能明白依赖的收集。
- Dep.target何时赋值: 管家类有个方法:
export function pushTarget (target: ?Watcher) {
targetStack.push(target)
Dep.target = target
}
它何时被调用了,那么回到Vue的初始方法那边,初始化数据对象后,需要干嘛?需要挂载DOM元素。
所以去挂载处理里面需要答案。
$mount => mountComponent => updateComponent赋值(render函数执行)=> new Watcher() => 依赖收集 => render执行
一个组件,一个Watcher
get () {
// 管家与Watcher依赖收集
pushTarget(this)
const vm = this.vm
value = this.getter.call(vm, vm)
popTarget()
this.cleanupDeps()
return value
}
这时 Dep.target 就被赋值了,然后调用Dom的渲染函数时,相关的数据被调用是,就会触发下方的判断,并建立关系:
get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val
**// 这时watcher
if (Dep.target) {
**// 这行代码又是啥?**
dep.depend()
// 子ob也要和当前watcher建立关系
if (childOb) {
childOb.dep.depend()
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
}
就是当Watcher对象存在时,就在 数据的管家中 记录关联组件的Watcher对象。包含数据的子对象也要记录关联。当这个数据被变换时, 就从通过dep管家通知相关的Watcher。
- 总结