Vue双向数据绑定的核心和基础api是Object.defineProperty,其内部真正参与数据双向绑定流程的主要有Obderver、Dep和Watcher,基于defineProperty和观察者模式,最终实现数据的双向绑定。
一、 为什么进行收集依赖?
new Vue({
data(){
return {
name:'zane',
gender:'男'
}
} })
有上面这个date,如果实际上页面只使用到了name,并没有使用gender,根据Object.defineProperty的转换,如果我们设置了this.gender='女',那么Vue也会去执行一遍虚拟DOM的比较,这样就无形的浪费了一些性能,因此才需要做依赖收集,界面用到了就收集,没有用到就不收集。
二、收集依赖的过程
Object.defineProperty
直接看observer的方法
进入到 dep.js 看看dep.depend()方法的实现。
上面两处都用到了 Dep.target ,它就是一个Watcher实例化对象( 全局 )。
搞懂了Dep.target等于一个Watche对象,现在继续回到之前的思路看watcher.addDep做了什么。
注意,可能会对这里产生疑问,按照如图的流程,那么push进去的只有全局watcher对象,按照当前的流程是这样的,但是还会有其他的watcher,但不是按照这个流程进入到subs里面的,如果现在不太理解,等读完整个流程回过来看看可能就懂了。
就这样依赖收集的流程就走完了,是否感觉很绕。
总结:
依赖收集最终在 watcher.newDeps 中push了闭包中传过来的dep对象,在dep.subs中push了初始化Vue是全局的Watcher对象,这个对象的,this.getter = expOrFn,传过来的expOrFn是后期数据更新页面渲染的核心步骤,需要沉下心来好好去理理。
分步解析:
三、视图更新过程
defineReactive set 去触发
后面会调用vm.patch 方法,进而执行虚拟DOM的diff过程实时的更新界面。
理解
- 每个组件全局有一个 watcher ( 必 ) ( 全局就是app也有 )
- 如果对某数据有 watch 或者 computed 的操作,那么就会有多个 watcher
- 每一个被渲染出的数据对应一个 dep, dep 会存在相对应对的组件的全局 wacher 中, 当然,计算的 wacher 中也包含依赖计算数据的 dep
- 一个 dep 最基本的会对应一个渲染 watcher, 但是如果此数据有其他的计算依赖的话就会有多个 watcher