Vue源码解析系列——响应式原理篇:理解Dep类和Watcher类

回顾

如果有感兴趣的同学可以看看我之前的源码分析文章,这里呈上链接:《Vue源码分析系列:目录》

写在前面

这一篇我们先不着急阅读源码,因为接下来需要用到一个比较复杂的设计模式:观察者模式,而且还需要理解依赖收集派发更新才能继续向下阅读源码,所以这次我们先做一个铺垫。

依赖收集

通过之前阅读的源码我们了解到Vue2.x版本的响应式是依靠Object.defineProperty这个API来进行对象的劫持,当对象进行取值和赋值操作的时候,都可以进行一些另外的操作。在get过程中,也就是对象的取值,Vue做的操作是:依赖收集。
那么什么是依赖?
这里我们举一个例子:

<template>
	<div class="demo">
		{
     {
     message}}
	</div>
</template>

<script>
export default {
     
	name:"demo",
	data:() => ({
     
		message:"hello"
	})
}
</script>

在Vue的1.x版本中,对于依赖的定义分的很细,包括了模板元素上的{ {message}}和组件demo;而在2.x的版本中,以上面这个例子为例,data中的messagedemo组件依赖了。

在对data进行响应式构造的时候,需要使用依赖收集器将所有data的依赖收集起来。
在Vue中的依赖收集器的具体表现形式就是Dep类。

所以在data改变过程中,依赖收集器会通知这些依赖于data的项去触发更新。

class Dep

Dep类的具体作用是在数据的get过程中,收集数据的相关依赖项,用于之后的更新依赖操作。

其实在数据和依赖的中间还夹着一层,就是订阅者,订阅者的作用就是在数据的set过程中触发订阅者的通知方法,从而让订阅者去通知依赖更新。

所以,Dep实例的不会直接存放依赖项,Dep实例存放的其实是各个依赖项对应的watcher实例,由watcher实例去调用对应依赖项的更新。

在Vue中,订阅者的具体表现形式就是Watcher类。

class Watcher

Watcher是一个观察者类。
Watcher也会存储Dep,因为一个依赖项可能会依赖多个被依赖项,如一个Computed可能会使用到多个data。当其中任意一个被依赖项发生改变时,Watcher就会去通知相关依赖项的更新。
watcher类的通知依靠的是update方法,这个update方法就是主动去触发依赖的更新。那么这个update方法是怎么触发的呢?
在数据发生变化时,会调用Dep实例的notify方法,这个notify方法会去在自身实例上寻找依赖列表,这个依赖列表里面都是一个个的watcher,之后notify方法会遍历这个列表,逐个触发watcherupdate方法。

也就是说,真正的数据更新顺序是这样的:
配置data的响应式 -------> 实例化对应依赖的watcher -------> 触发get -------> 由Dep去收集相关的watcher ------->watcher收集当前的Dep -------> 页面交互 -------> 触发set -------> Dep通知watcher更新 -------> watcher更新依赖项。

官方的流程图

官方的图这里在datawatcher中间少了一个Dep,其实图中的NotifyCollect as Despendency都是由Dep实例做的。(可能是为了便于理解吧,故意省略了Dep类)
Vue源码解析系列——响应式原理篇:理解Dep类和Watcher类_第1张图片

总结

Vue响应式原理的难点其实就在于DepWatcher
Dep存储了多个WatcherWatcher又会存储多个Dep,是一个复杂的多对多的关系,这个在之后介绍computed原理时会体现得更加明显。
理解了DepWatcher类的关系,对我们接下来阅读源码有非常大的帮助。

你可能感兴趣的:(vue,源码)