Vue源码解析13--core.observer-观察者
2019-04-26
前端开发
Observer观察者
Vue要定义一个响应式的属性,本质上是改造其getter/setter。
对于getter,具体的操作是:
- 执行原本的getter(如果用户做了定义),获得value。
- 如果是响应式的属性,执行依赖收集,即将该
dep加入watcher.deps中,将watcher加入dep.subs中,交叉引用(当然也要做查重,避免加入重复的引用)。 - 深度(deep)模式下,它的成员也有observer,执行它对应的依赖收集。成员为Array的情况下,遍历它,并执行依赖收集。
- 返回 value。
对于setter,具体的操作是:
- 先触发getter,获得上一次的值,并收集依赖。
- 对比当前值和上一次的值,如果没变化,直接返回。
- 如果发生了变化,执行原本的setter(如果用户做了定义),完成赋值操作。
- 深度(deep)模式下,尝试为成员创建Observer。
- 操作它的
dep执行notify()方法,进而触发该dep下所有watcher的update()方法。
对于一个vm的更新,就可以描述为(假设修改了$data中的某个属性值):
- 触发该属性改造后的setter。
- setter中触发getter进行依赖收集,确认传入的值和之前不同,先执行原来定义的setter,然后触发这个属性的
dep(在defineReactive()的闭包中创建)发出notify()更新通知。 - 根据该
dep中dep.subs的记录,触发所有订阅这个dep的watcher的update方法。 - 在
watcher.update()中判断执行类型,通常$data属性改变触发的是由scheduler负责的queueWatcher(this)异步更新。 scheduler将这个watcher加入更新队列,nextTick()中flush整个队列,调用watcher.run()来执行更新。watcher.run()中执行该watcher的watcher.get()方法。watcher.get()中,执行this.getter(),即在lifecycle中mountComponent()在创建这个Watcher实例时,传入的updateComponent()方法,触发vm._update(vm._render(), hydrating)。vm._render()负责生成新的vnode,vm._update()对比新vnode和原vnode,执行patch算法,并将其挂载到组件的实例上去,更新完成。
建模
对于整个Observer模块,共有四个核心概念
Observer类,附着到每个被观察的对象,作为其__ob__属性,负责改造其属性为getter/setter形式。dep属性为其Dep,用于收集依赖并发出更新通知。Dep类,负责依赖收集和发布更新通知,可以让多个watcher去订阅它。它记录了所有订阅它的watcher,放在subs中。其静态属性Dep.target用于指示当前正在执行的watcher。Watcher类,解析getter表达式,收集依赖,并且在getter所指向的值发生改变时触发回调。computedWatcher放在vm._computedWatchers中,其他watcher放在vm._watchers中,vm中负责render的watcher为vm._watcher。Scheduler调度器,用于记录当前tick下需要进行异步更新的watcher队列,调度这些watcher的异步更新,在nexttick()中执行。执行完成后,触发对应vm的activated和updated钩子,并清理现场。