computed
的初始化过程,会遍历computed
的每一个属性值,并为每一个属性实例化一个computed watcher
,其中{ lazy: true}
是computed watcher
的标志,最终会调用defineComputed
将数据设置为响应式数据,对应源码如下:
defineComputed
的逻辑和分析data
的逻辑相似,最终调用Object.defineProperty
进行数据拦截。具体的定义如下:
在非服务端渲染的情形,计算属性的计算结果会被缓存,缓存的意义在于,只有在相关响应式数据发生变化时,computed
才会重新求值,其余情况多次访问计算属性的值都会返回之前计算的结果,这就是缓存的优化,computed
属性有两种写法,一种是函数,另一种是对象,其中对象的写法需要提供getter
和setter
方法。
createComputedGetter
返回的函数在执行过程中会先拿到属性的computed watcher
,dirty
是标志是否已经执行过计算结果,如果执行过则不会执行watcher.evaluate
重复计算,这也是缓存的原理。
get
方法前面介绍过,会调用实例化时传递的执行函数,在computer watcher
的场景下,执行函数是计算属性的计算函数,他可以是一个函数,也可以是对象的getter
方法。
这就是computed
依赖收集的完整过程,对比data
的依赖收集,computed
会对运算的结果进行缓存,避免重复执行运算过程。
7.10.2 派发更新
派发更新的条件是data
中数据发生改变,所以大部分的逻辑和分析data
时一致,我们做一个总结。
- 当计算属性依赖的数据发生更新时,由于数据的
Dep
收集过computed watch
这个依赖,所以会调用dep
的notify
方法,对依赖进行状态更新。
由于lazy
属性的存在,update
过程不会执行状态更新的操作,只会将dirty
标记为true
。
- 由于
data
数据拥有渲染watcher
这个依赖,所以同时会执行updateComponent
进行视图重新渲染,而render
过程中会访问到计算属性,此时由于值为true
,又会对计算属性重新求值。