vue - obsever dep watcher

325 阅读2分钟

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的方法

image

进入到 dep.js 看看dep.depend()方法的实现。

image

上面两处都用到了 Dep.target ,它就是一个Watcher实例化对象( 全局 )。

image

image

image

搞懂了Dep.target等于一个Watche对象,现在继续回到之前的思路看watcher.addDep做了什么。

image.png

image

注意,可能会对这里产生疑问,按照如图的流程,那么push进去的只有全局watcher对象,按照当前的流程是这样的,但是还会有其他的watcher,但不是按照这个流程进入到subs里面的,如果现在不太理解,等读完整个流程回过来看看可能就懂了。

就这样依赖收集的流程就走完了,是否感觉很绕。

总结:

    依赖收集最终在 watcher.newDeps 中push了闭包中传过来的dep对象,在dep.subs中push了初始化Vue是全局的Watcher对象,这个对象的,this.getter = expOrFn,传过来的expOrFn是后期数据更新页面渲染的核心步骤,需要沉下心来好好去理理。

分步解析:

image.png

三、视图更新过程

defineReactive set 去触发

image.png

image.png

image.png

image.png

image.png

image.png

后面会调用vm.patch 方法,进而执行虚拟DOM的diff过程实时的更新界面。

image.png

理解

  1. 每个组件全局有一个  watcher ( 必 ) ( 全局就是app也有 )
  2. 如果对某数据有 watch 或者 computed 的操作,那么就会有多个  watcher
  3. 每一个被渲染出的数据对应一个 dep, dep 会存在相对应对的组件的全局 wacher 中, 当然,计算的 wacher 中也包含依赖计算数据的 dep
  4. 一个 dep 最基本的会对应一个渲染 watcher, 但是如果此数据有其他的计算依赖的话就会有多个 watcher

对应关系

image.png