前言
对于使用 vue 技术栈开发的前端工程师来说,面试中经常会被问到 watch 和 computed 的区别是什么,是否有了解过 computed 实现原理。那么我们就来看下,computed 的原理以及它是如何实现缓存的。
阅读此篇文章需要了解 vue2.X 的响应式原理,掘金也有很多文章,大家自行阅读~
1. vue 项目中的基本使用
在 vue 项目中我们经常在组件这样使用
<template>
<div class="container">
{{ name }}
</div>
</template>
<script>
export default {
data () {
return {
firstname: 'yang',
lastname: 'yusi'
};
},
computed: {
name() {
return this.firstname + this.lastname;
}
},
}
</script>
我们知道,当组件初始化的时候,首先会调用 initState 方法对 props, data, computed, watch 中的定义的数据添加响应式,当数据变化的时候,会通知视图进行更新(参考 vue 响应式原理)。
下面我们具体分析下当 firstname 或者 lastname 变化的时候,name 的值也会进行重新计算。以及当 firstname 和 lastname 值不发生变化时,name 是如何获取缓存值的。
根据上图可以知道,initState 的时候,会对组件的 computed 属性进行初始化,即 initComputed 方法。
执行 defineComputed 方法后通过条件判断 ,我们的 userDef === 'function' ,所以会执行 createComputedGetter('name') 方法。
lazy 为什么时是 true,请看
是手动设置的
下面是 watcher 的 evaluate 方法
会触发 watcher 的 get 方法,此时会执行
function () {
this.firstname + this.lastname;
}
读取 firstname 和 lastname 的值,会触发他们的 getter 方法,同时会把此时的 watcher 分别收集到他们的 Dep 依赖列表中 , 那么当他们的值发生变化,就会触发 setter 方法,触发 water 的 update 方法,
之前设置 lazy 为 true ,那么会设置 dirty 为true, 更新name 的值,并且会触发视图的更新。 这也就是 computed 的原理。
还剩下一个问题, computed 是如何实现缓存的呢? 当我们第一次获取到name 的值时, 设置了dirty = true, 当我们再次读取 name 的值时, 会直接读取Watcher的value值,也就是初始化时获取的值。
如有不正,欢迎评论指出~~