1.computed大致流程
computed是vue中的计算属性,在依赖的值发生变化的时候进行重新计算,否则使用缓存。
而在面试中常被问及computed原理,这篇文章主要作为我学习computed源码的笔记。
前面说到computed只有在依赖发生变化才会重新计算,那么如何得知computed的值发生了变化呢
这主要是Watcher中的dirty属性,dirty属性为true时,说明computed中的值需要重新计算,dirty为false时,则说明依赖没有变化,不需要重新计算
当计算属性的值发生变化时,计算属性的watcher和组件的watcher都会得到通知。
计算属性的watcher会将dirty置为true,组件的Watcher得到通知,同样将dirty属性置为false,重新计算值,用于本次渲染。
简单来说,computed就是定义在vm上的一个getter属性,这个getter属性被触发时会做两件事
1. 计算当前属性的值,此时会使用Watcher去观察计算属性中用到的所有其他数据的变化。同时将计算属性的Watcher的dirty属性设置为false.
2.当计算属性中用到的数据发生变化时,将得到通知从而进行重新渲染
Watcher中的depend和evaluate方法是专门用于实现计算属性的两个API
export default class Watcher {
constructor(vm, expOrFn, cb, options) {
if(options) {
this.lazy = !!options.lazy;
} else {
this.lazy = false;
}
this.dirty = this.lazy;
this.value = this.lazy ? undefined : this.get()
}
evaluate() {
this.value = this.get()
this.dirty = false;
}
depend() {
let i = this.deps.length
while(i--) {
this.deps[i].depend()
}
}
}
执行depend方法可以将组件中的watcher实例添加到dep实例的依赖列表中。换句话说,this.deps是计算属性中用到的所有状态的dep实例,而依次执行了dep实例的depend方法就是将组件的watcher依次加入到这些dep实例的依赖列表。这就实现了让组件的watcher观察计算属性中用到的所有的状态的变化。
2.Computed逻辑变化
computed在vue2.5.2中的实现发生了一些变化,因为之前的computed的计算存在一些逻辑上的漏洞,因为只要依赖的值发生了变化,vue就认为值发生了变化,组件会重新走一遍渲染的流程,但实际上UI不会由变化,浪费了一些性能。
改动之后的逻辑:
组件的watcher不再监听计算属性的变化,而是让计算属性的watcher得到通知后,计算一次计算属性的值,如果发现这一次计算出来的值与上一次计算出来的值不一样,再去主动通知组件的watcher进行重新渲染。