好家伙,
1.Computed实现原理
if (opts.computed) { initComputed(vm,opts.computed); } function initComputed(vm, computed) { // 存放计算属性的watcher const watchers = vm._computedWatchers = {}; for (const key in computed) { const userDef = computed[key]; // 获取get方法 const getter = typeof userDef === 'function' ? userDef : userDef.get; // 创建计算属性watcher watchers[key] = new Watcher(vm, userDef, () => {}, { lazy: true }); defineComputed(vm, key, userDef) } }
computed依赖跟踪的处理逻辑与watcher相似
1.1.watcher
每个计算属性也都是一个watcher
,计算属性需要表示lazy:true,这样在初始化watcher时不会立即调用计算属性方法
class Watcher { constructor(vm, exprOrFn, callback, options) { this.vm = vm; this.dirty = this.lazy // ... this.value = this.lazy ? undefined : this.get(); // 调用get方法 会让渲染watcher执行 } }
1.2.dirty属性
默认计算属性需要保存一个dirty属性,用来实现缓存功能
function defineComputed(target, key, userDef) { if (typeof userDef === 'function') { sharedPropertyDefinition.get = createComputedGetter(key) } else { sharedPropertyDefinition.get = createComputedGetter(userDef.get); sharedPropertyDefinition.set = userDef.set; } // 使用defineProperty定义 Object.defineProperty(target, key, sharedPropertyDefinition) } function createComputedGetter(key) { return function computedGetter() { const watcher = this._computedWatchers[key]; if (watcher) { if (watcher.dirty) { // 如果dirty为true watcher.evaluate();// 计算出新值,并将dirty 更新为false } // 如果依赖的值不发生变化,则返回上次计算的结果 return watcher.value } } }
为什么使用缓存?
1.减少不必要的计算开销:计算属性的值是根据依赖的响应式数据计算而来的。如果每次访问计算属性都重新计算一次,无论依赖数据有没有变化,都会导致不必要的计算开销。
通过使用 dirty
属性,可以标记计算属性是否需要重新计算,从而避免不必要的计算。
2.提高性能与响应速度:通过缓存计算属性的值,当访问计算属性时,如果依赖数据没有发生改变,可以直接返回之前的缓存值,而不必重新计算。
这样可以提高性能并且快速响应用户的数据访问请求。
3.依赖数据发生变化时再重新计算:当依赖的响应式数据发生变化时,计算属性才需要重新计算。
通过将 dirty
属性设置为 true
,可以在下一次访问计算属性时触发重新计算,并将计算结果缓存起来。
1.3.watcher.evaluate()方法
evaluate() { this.value = this.get() this.dirty = false } update() { if (this.lazy) { this.dirty = true; } else { queueWatcher(this); //更新方法 } }
当依赖的属性变化时,会通知watcher调用update方法,此时我们将dirty置换为true。这样再取值时会重新进行计算。
if (watcher) { if (watcher.dirty) { watcher.evaluate(); } if (Dep.target) { // 计算属性在模板中使用 则存在Dep.target watcher.depend() } return watcher.value } depend() { let i = this.deps.length while (i--) { this.deps[i].depend() } }
如果计算属性在模板中使用,就让计算属性中依赖的数据也记录渲染watcher,这样依赖的属性发生变化也可以让视图进行刷新
标签:key,userDef,Vue,computed,watcher,源码,dirty,计算,属性 From: https://www.cnblogs.com/FatTiger4399/p/17766224.html