Dep的定义还是非常清晰的,代码注释如上,很明显Dep跟Watcher就跟捆绑销售一样,互相依赖。我们在分析denfineReactive的时候,在对数据进行响应式操作的时候,通过Object.defineProperty重写了getter函数。
Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter () { const value = getter ? getter.call(obj) : val if (Dep.target) { // 当前的全部的Watcher实例 dep.depend() // 把当前的Dep.target加入到dep.subs数组中 // .. } return value },
其中的dep.depend()实际上就是执行了Dep.target.addDep(this),this指向Dep实例,而Dep.target是一个Watcher实例,即执行watcher.addDep(this)函数。我们接下来在看看这个函数做了什么:
class Watcher { addDep (dep: Dep) { const id = dep.id if (!this.newDepIds.has(id)) { this.newDepIds.add(id) this.newDeps.push(dep) // if (!this.depIds.has(id)) { dep.addSub(this) // 会把watcher插入到dep.subs数组中 } } } }
可以通过下图以便理解data、Dep、Watcher的关系:
回到代码中,其中dep.addSub(this)就是会把当前的wathcer实例插入到dep.subs的数组中,为之后的派发更新做好准备,这样依赖收集就完成了。但是到现在为止,我们只分析了依赖收集是怎么实现的,但是依赖收集的时机又是在什么时候呢?什么时候会触发getter函数进而实现依赖收集的?在进行依赖收集的时候,Dep.tagrget对应wathcer又是什么呢?
Watcher大致可以分为三类: * 渲染Watcher: 每一个实例对应唯一的一个(有且只有一个) * computed Watcher: 每一个实例可以有多个,由computed属性生成的(computed有多少个keyy,实例就有多少个computedWatcher) * user Watcher: 每一个实例可以有多个,由watch属性生成的(同computed一样,userWatcher的数量由key数量决定) 为避免混淆,我们接下来说的Watcher都是渲染Watcher。我们知道在Vue初始化的过程中,在执行mountComponent函数的时候,会执行new Watcher(vm, updateComponent, {}, true),这里的Watcher就是渲染Watcher
class Wachter { get () { pushTarget(this) // Dep.target = this let value const vm = this.vm try { value = this.getter.call(vm, vm) // 更新视图 } catch (e) { if (this.user) { handleError(e, vm, `getter for watcher "${this.expression}"`) } else { throw e } } finally { // "touch" every property so they are all tracked as // dependencies for deep watching if (this.deep) { traverse(value) } popTarget() this.cleanupDeps() } return value } }
new Watcher对于渲染watcher而言,会直接执行this.get()方法,然后执行pushTarget(this),所以当前的Dep.target为渲染watcher(用于更新视图)。 而在我们执行this.getter的时候,会调用render函数,此时会读取vm实例上的data数据,这个时候就触发了getter函数了,从而进行了依赖收集,这就是依赖收集的时机,比如
{{ message }} // 会读取vm._data.message, 触发getters函数
派发更新
我们继续来看defineReactive函数里
export function defineReactive ( obj: Object, key: string, val: any, customSetter?: ?Function, shallow?: boolean ) { const dep = new Dep() // .. Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter () { // .. }, set: function reactiveSetter (newVal) { /* eslint-disable no-self-compare */ if (newVal === value || (newVal !== newVal && value !== value)) { return } /* eslint-enable no-self-compare */ if (process.env.NODE_ENV !== 'production' && customSetter) { customSetter() } // #7981: for accessor properties without setter if (getter && !setter) return if (setter) { setter.call(obj, newVal)https://cn.vuejs.org//images/data.png } else { val = newVal } childOb = !shallow && observe(newVal) dep.notify() // 遍历dep.subs数组,取出所有的wathcer执行update操作 } }) }