前面也已经写过vue的依赖收集和派发更新的源码讲解了,但是估计很多不了解的人看的仍然一头雾水,还是不能明白整个流程是怎样的。因此我又花了一些时间来弄懂这块梳理成图,阅读性也更好一些。 话不多说,开始上图了:
依赖收集
这里给大家备注一下某些变量的作用:
subs: Dep类创建的,用于存放所有被收集的依赖即watcher,将依赖存放在subs中,目的是后面数据发生变化的时候能够通知那些subs做出准备。 watcher中定义的:
- newDeps:表示新添加的Dep实例数组
- deps:表示上一次添加的Dep实例数组
- newDepIds:表示在最新的 addDep过程中,收集的 dep id
- depIds:表示在 上一次addDep 过程中,收集的 dep id。
为什么vue要创建两个Dep实例数组? 因为Vue是数据驱动的,所以每次数据变化都会重新render,那么 vm._render() 方法又会再次执行,并再次触发数据的 getters,所以 Watcher 在构造函数中会初始化 2 个 Dep 实例数组。目的是在 在执行 cleanupDeps 函数的时候,会首先遍历 deps,移除对 dep.subs 数组中 Wathcer 的订阅,然后把 newDepIds 和 depIds 交换,newDeps 和 deps 交换,并把 newDepIds 和 newDeps 清空。避免渲染不必要的数据,提升了性能。
派发更新
queueWatcher:就是将watcher 去重,然后添加到队列中。然后执行nextTick(flushSchedulerQueue) 异步更新。
flushSchedulerQueue:这个方法简单来说就是对queue 队列排序,然后遍历该数组,执行watcher.run() 。
watcher.run():这个run() 方法其实最终就是调用了watcher 的get 方法,这个get 我们在前面看过了,最主要的就是去调用了data 数据的get 方法,获取最新数据。因此我们可以理解run() 就会进行新一轮的依赖收集,从而获取最新的数据。
最后我们简单总结一下依赖收集和派发更新: 当访问响应式数据时,触发getter,调用dep.depend()进行依赖收集到subs中,这个过程我们叫依赖收集;而当这些响应式数据发生变化,触发它们的 setter 的时候,能知道应该通知哪些订阅者去做相应的逻辑处理,我们把这个过程叫派发更新。 Watcher 和 Dep 就是一个非常经典的观察者设计模式的实现,这里我们暂时先不讲,后面有空的话我会补上哦!
感谢大家的浏览,希望对你们有用!谢谢
|