一次搞懂vue中computed原理

302 阅读2分钟

前言

对于使用 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 是如何获取缓存值的。

image.png

根据上图可以知道,initState 的时候,会对组件的 computed 属性进行初始化,即 initComputed 方法。

image.png

执行 defineComputed 方法后通过条件判断 ,我们的 userDef === 'function' ,所以会执行 createComputedGetter('name') 方法。

image.png

lazy 为什么时是 true,请看

image.png

是手动设置的

下面是 watcher 的 evaluate 方法

image.png

会触发 watcher 的 get 方法,此时会执行

function () {
    this.firstname + this.lastname;
}

读取 firstname 和 lastname 的值,会触发他们的 getter 方法,同时会把此时的 watcher 分别收集到他们的 Dep 依赖列表中 , 那么当他们的值发生变化,就会触发 setter 方法,触发 water 的 update 方法,

image.png

之前设置 lazy 为 true ,那么会设置 dirty 为true, 更新name 的值,并且会触发视图的更新。 这也就是 computed 的原理。

还剩下一个问题, computed 是如何实现缓存的呢? 当我们第一次获取到name 的值时, 设置了dirty = true, 当我们再次读取 name 的值时, 会直接读取Watcher的value值,也就是初始化时获取的值。

如有不正,欢迎评论指出~~