vue中computed 缓存原理

文章类型:Vue

发布者:hp

发布时间:2023-05-22

一:定义

1:computed属性可以用于定义计算属性,它的特点是具有缓存机制,即只有依赖的响应式数据发生变化时,才会重新计算

2:缓存机制本质是通过一个dirty属性控制的,dirty只有当其响应式数据发送变化时才会设置为true,重新计算后会再次被设置为false

二:原理

1:vue初次运行会对computed进行初始化处理(initComputed)

if (opts.computed) {initComputed(vm, opts.computed);}

2:会对每一个computed属性用watcher包装起来

var watchers = vm._computedWatchers = Object.create(null); 
// 依次为每个 computed 属性定义一个计算watcher
for (const key in computed) {
  const userDef = computed[key]
  watchers[key] = new Watcher(
      vm, // 实例
      getter, // 用户传入的求值函数 
      noop, // 回调函数 可以先忽视
      { lazy: true } // 声明 lazy 属性 标记 computed watcher
  )
 
}

2:会生成一个dirty属性值为true

{
    deps: [],
    dirty: true,
    getter: ƒ sum(),
    lazy: true,
    value: undefined
}

4:在使用数据的时候,则进行触发

 defineComputed(vm, key, userDef)

5:根据dirty值来进行判断是否重新计算,有变化,computed 的 watcher 会把 dirty 变为 true,计算完成后便会false,否则就不改变

 Object.defineProperty(target, key, { 
    get() {
        // 从刚刚说过的组件实例上拿到 computed watcher
        const watcher = this._computedWatchers && this._computedWatchers[key]
        if (watcher) {
          // 只有dirty了才会重新求值
          if (watcher.dirty) {
            // 这里会求值,会调用get,会设置Dep.target
            watcher.evaluate()
          }
          // 
          if (Dep.target) {
            watcher.depend()
          }
          // 最后返回计算出来的值
          return watcher.value
        }
    }
})

6:有变化,则执行watcher.evaluate(),就会有一个读取操作,然后把dirty值设置为false

evaluate () {
  // 调用 get 函数求值
  this.value = this.get()
  // 把 dirty 标记为 false
  this.dirty = false
}

三:代码

computed: {
      sum() {
        return this.count + 1
      },
    },

四:总结

1:避免不必要的计算,提高性能

2:当数据没发生变化是,每次会返回相同的缓存值,(避免产生副作用)

3:要在计算属性中进行异步操作或需要在每次访问时重新计算的情况下,可以考虑使用watch属性