响应式原理
组件渲染的过程做了两件事组件的实例化和mount
实例化:会遍历data和props上的每一个属性,使用defineProperty(vue3.0实现proxy)把它变为响应式的,同时实例化一个Dep(收集Watcher和通知Watcher渲染元素)。
mount:会实例化一个渲染Watcher然后渲染元素,在render的过程中会访问到元素中的动态数据,这个时候Dep会对当前渲染Watcher完成收集
当某个属性变化的时候,这个属性的Dep会通知Watcher更新dom元素
响应式原理使用的设计模式
可以发现vue结合了观察者模式和订阅发布模式实现了响应式原理
观察者模式:在实例化的时候,把数据变为响应式的,从而实现对数据的监听
订阅发布模式:在访问数据的时候Watcher订阅了Dep的变化,在数据变化的时候发布者Dep通知Watcher更新
依赖收集
数据一访问就进行Dep对Watcher收集吗?组件渲染Watcher不在依赖某个Dep,什么时候去除Dep对Wacher的收集?先看一个例子:
<div v-if="flag">
<div>{{a}}</div>
</div>
<div v-else>
<div>{{b}}</div>
</div>
在第一渲染的时候,属性flag和a的Dep收集了Watcher,当flag变为false的时候属性b又会收集Wachter,而这时候a属性是我们不想依赖的。所以,真正收集依赖的过程是在所有数据访问完之后收集,因为这个时候才能和上次比较哪些依赖的数据发生了变化,把上次依赖的本次不再依赖的数据,让它的Dep移除对Watcher的收集。
watch和computed
在组件实例化的时候也会对watch和computed进行一些初始化的操作
watch
watch的作用:监听一个响应式数据的变化,执行定义的方法
watch的收集:在watch初始化的时候会遍历watch上定义的每个属性(这个属性是响应式的,已经生成Dep),然后实例化一个user Wachter(把watch上的属性和方法传进去),在实例化的过程中访问watch的属性,实现对user Wachter的依赖收集。
watch的更新:当watch中定义的响应式的属性变化时,通知 user Wachter执行该属性定义的方法
computed
computed的作用:定义的方法里面的响应式数据的变化会触发这个方法的执行,生成一个新的值,和旧值比较如果变了,间接影响渲染Wachter的更新。
computed的收集:computed初始化的时候会computed上的遍历属性调用defineProperty使它变为响应式,然后实例化一个computed Watcher。再render阶段访问dom元素上computed的属性的时候,会触发defineProperty的get方法。在get方法中,会调用computed属性对应的方法,当访问方法中的响应式属性的时候,会对computed Watcher进行依赖收集。同时,computed Watcher也会有一个自己属性Dep,对渲染Watcher进行依赖收集。
computed的更新:computed中定义的方法中响应式数据变化的时候,会通知computed Watcher的更新,也就是执行computed中定义的方法,如果和旧值比较发现变化,又会触发渲染Wachter的更新。