user-watcher
在页面中使用的watcher,即用户定义的watcher,用于观察一个属性的更新,支持数组定义多个,对象定义单个的形式,在initWatcher中进行watcher的初始化之后,在渲染函数进行数据的读取,触发依赖收集时会将user-watcher的依赖收集进去,data属性set更新时会被触发user-watcher所定义的回调函数(将新旧值传入),支持异步操作
可选项:immediate deep sync
- immediate为true时会将实例作为参数传入立即执行回调函数
- deep 对对象、数组进行深度的依赖收集
- sync 不把更新watcher放到nextTick队列 而是立即执行更新
render-watcher
每一个组件都有一个render-watcher当data/computed中的有被依赖的属性改变的时候会触发render-watcher的更新,表达式为function(){vm._update(vm.render(), hydrating)}
- 使用:在组件嵌套中,props触发的关联更新等,如父组件会将子组件的watcher收集用于视图更新的触发
- 初始化:渲染函数的watcher,mounted之后,实例化初始化染函数观察者并触发对render-wather的收集,渲染函数也是一个对象,初始化过程,生成render-tree,获取结果时收集render-watcher依赖,render-tree更新也就是需要重新渲染视图
- 防止重新收集:this.depIds.has(dep.id)来避免重复依赖收集,因在渲染函数中,一个属性被引用多次是常见的
- 更新:data更新触发依赖,同时会触发user-watcher对回调函数完成新旧数据的派发,最后触发render-watcher更新视图,所有的watcher默认都是在nextTick队列中进行异步更新的,当所有的突变完成之后,一次性的执行队列中所有观察者的更新方法,同时清空队列,这样 多次更新同一个watcher只会更新一次,而频繁的更新可以整合为一次
computed-watcher
- 使用:在initState阶段被初始化,具有缓存性质的惰性求值观察者,只有存在依赖性数据并且该数据更新了,computed值才会更新,否则就取缓存的值,依赖数据是data中的数据
-初始化:computed 计算属性在mounted之后生成,实例化computed-watcher 初始化computed dirty属性为true,并不调用get方法读取属性 - 计算:当渲染函数访问到computed属性,进行求值,并将dirty设置为false标识计算过,同时对依赖的属性读取时将computed-watcher当做依赖收集,并且订阅render-watcher,所以在内部数据触发set时会先计算后对比新旧值,有更新则重新渲染视图
- 更新:内部依赖被触发后,设置dirty为true,通过判断this.dep.subs.length 有没有订阅者,如果有则进行取值的计算(计算后将dirty置为false),否则等待该值被引用才进行计算
总结
这三种watcher执行顺序为computed watcher => user watcher => render watcher,这样做 尽可能的保证了视图更新时数据是最新的
收集依赖是在render tree渲染时读取render tree的结构,触发依赖的收集,每一次都只会对一个观察者进行操作,所以一个时间点只有一个Dep.tatget,说明这个观察者是依赖于当前的数据,就会把这个观察者添加到该数据的subs里面,会通过id来防止重复添加,同时会将依赖添加到自身的deps中以便通过set调用dep.notify()
什么时候触发了依赖的收集
-
准备:在created和beforeMounted之间生成了AST和render可执行函数,用到了compile的createCompiler生成对象结构的AST语法树,再通过generator调用了之前初始化的方法处理各种vue内置的方法&指令,如v-for v-if等,通过createElement、createTextVnode等生成虚拟DOM树,作为updateComponent函数返回
-
渲染:在beforeMounted和mounted之间通过将执行这个函数,这个函数会将虚拟DOM渲染成真正的DOM,内含有patch的布丁算法,在执行过程中会触发渲染函数,这时会触发数据属性的get函数,而这个过程的观察者就是渲染函数,在渲染过程中添加数据的订阅者,watcher订阅者是Observer和Compiler之间的桥梁,将在自身实例化的时候将自己添加到dep当中,watcher自身有一个depend和update方法,待属性变动dep.notice通知调用自身的update方法触发Compile中绑定的回调
实现:https://blog.csdn.net/wangweianger/article/details/80307819
网友评论