依赖收集
当访问对象属性的时候,会触发定义的getter
在defineReactive中,给属性添加的get逻辑主要就是负责依赖收集
Dep
Dep是一个类,是数据和watcher之间的桥梁
1 | // src/core/instance/observer/dep.js |
Dep.target是当前的watcher,唯一
Watcher
1 | // src/core/instance/observer/watcher.js |
触发get的时机
在执行mountComponent的时候,会实例化一个Watcher对象(渲染watcher),并把updateComponent函数传入其中,如果是函数
1 | // Watcher的get方法 |
在Watcher实例化的过程中,会执行到this.get(),pushTarget(this)将当前渲染watcher赋值给Dep.target并推入栈中,以便之后回复上一个父状态,之后执行之前传入的updateComponent => vm.update(vm._render(), hydrating)
触发了render,在render的时候就会触发在模板中使用到的数据的getter,而此时Dep.target就是之前实例化的渲染watcher
defineReactive中添加的get:
1 | get: function reactiveGetter () { |
如果depsubs中没有这个watcher,将这个watcherpush进去
总结
上节说到,在创建响应式对象的时候,会给每个属性添加__ob__属性,这个属性就是一个Dep的实例,dep对象的作用就是收集了所有该属性的watcher,之后在set的时候去触发所有的watcher来通知改变的发生
派发更新
在修改数据的时候,会触发在defineReactive中的set逻辑
1 | set: function reactiveSetter (newVal) { |
notify方法就是遍历dep实例subs属性中存的watcher对象数组,分别触发他们的update方法
1 | // watcher.js update方法 |
包括计算属性、同步过程和其它情况,本节应该进入的是queueWatcher
1 | // observer/scheduler.js queueWatcher 方法 |
如果watcher不在全局的队列中,push进去
1 | // watcher run |
渲染watcher派发更新执行过程
数据set=>dep.notify()=>watcher.update()=>渲染watcher:queueWatcher()=>flushSchedulerQueue()=>watcher.run()=>watcher.getAndInvoke()=>watcher.get()=>watcher.get()=>watcher.getter()=>getter = expOrFn(创建watcher实例传入的第二个参数)=>updateComponent()=>vm._update()
总结
- 在对
props、data等数据初始化过程中,会调用observe方法使其中的数据变为响应式对象 observe方法初始化一个Observer类的实例,传入需要观测的对象Observer对象初始化过程中在观测的数据上添加__ob__属性,并将自身的值赋给__ob__;再对观测数据是数组的情况特别处理,保证属性是对象的情况也被观测到。最终对对象里的每一个值调用defineReactivedefineReactive会将传入的对象变成一个响应式对象,添加getter和setter- 在
get中,调用dep(dep在defineReactive函数的闭包中会被保存)的depend方法,将Dep.target(当前的watcher对象)保存在subs属性中,用于之后派发更新触发所有wathcer对象update - 在
set中,调用闭包中dep对象的notify方法,循环subs属性中所有的watcher,调用update;在渲染watcher的update中,调用queueWatcher将要更新的watcherpush到一个队列中,在nextTick的时候调用flushScedulerQueueflushSchedulerQueue会对queue以watcher的id大小排序,保证渲染顺序,并调用watcher.run()run方法又调用getAndInvoke方法,在渲染watcher的情况下,调用watcher实例的get方法,调用了getter属性(实例化watcher时传入的第二个参数),在渲染watcher的情况下就是updateComponent方法,最终触发vm._update开始重新渲染