阅读 97

Vue中的watcher之渲染 watcher和users watcher

上一篇文章介绍了一下计算属性实现的原理:lazy watcher

这篇补充下剩下的两种watcher:渲染watcher和users wat/cher

其实理解了计算属性之后,剩下的这两种watcher的运行过程就很容易理解了

渲染/render watcher

在mountComponent方法中存在这么一段:

这个new的watcher就是渲染watcher,而且有一个before属性,挂载一个beforeUpdate钩子

在watcher的构造函数中有这么一行,这说明在构造支出就会调用get方法进行一次依赖收集。因此组件的data就和watcher进行了初次绑定。

watcher.get

get方法本质上对于渲染watcher而言就是运行了vm._update方法,在调用的过程中会进行首次依赖收集。

重点是pushTarget与popTarget方法。这对于依赖收集而言很重要

targetStack

Dep.target是全局对象,是当前时刻watcher.get方法的调用者,对于组件渲染过程而言就是渲染watcher。

值得注意的是targetStack这个东西。因为对于父子组件而言,渲染函数纯在一个嵌套的关系。也就是说父组件渲染到一半的时候,会去渲染自组建,如果此时不更换全局的watcher,那么依赖收集必然发生错误,因此使用了栈结构去保存渲染watcher。

渲染watcher小结

由于初始化渲染watcher的时候就已经进行了依赖收集,那么以后数据更新后就会同计算属性一样去触发update方法以更新视图,update方法最后还是会调用get方法。整套流程就是不停地在进行依赖收集与派发更新。

另外一个值得在意的就是targetStack这个栈结构存在的意义就是在于解决以组件为粒度的更新时依赖收集错误状况出现。

users watcher

在初始化组件的时候,会对watch对象做如下处理,其实就是为每一个key创建一个watcher实例。同样地,大部分情况下创建过程都会有进行一次依赖收集。

注意: 这里用的vm.$watcher方法

vm.$watch

注意这里的immediatly

上方函数中createWatcher传入的key应着就是一个字符串或者一个表达式,对于传入expOrFn为字符串的时候,会解析路径直接获取对象的值。

createWatcher传入的handler函数就是传入watcher构造函数的cb,因此在run方法中,会执行这个cb(handler)函数,以拿到更新前后的值。

options

对于users watcher而言,有更多的选项可以对wathcer进行设置。

1. deep就递归获取侦听对象的值,在侦听过程中进行一次依赖收集,所有的值都收集当前watcher

2. lazy就是计算属性用到的lazy值

3. sync表明是否同步调用wathcer的run方法(一般都会把当前watcher加入queue队列进行异步更新)

4. before 在异步队列中进行watcher进行更新前调用的方法

5. user 标记是否为users watcher

6. immediatly 在vm.$watch方法中 如果immediatly为true,那么会立即调用一次cb/handler函数,而不是异步调用

users watcher小结

users watcher有更高的灵活度,当其expOrFn为vm._update,before为beforUpdate钩子函数时,它就是一个渲染watcher;当它的expOrFn为一个函数,且lazy属性为true时,就是一个计算属性。