默认computed也是一个watcher,具备缓存,只有当依赖的属性发生变化才会更新视图。
原理图:

流程:computed watcher在defineReactive的get中订阅属性的变化(4),在defineReactive的set时触发notify(4),notify调用每个订阅了改属性变化的watcher的update(3),update中将computed watcher 的dirty赋值为true(2),notify中其中一个watcher为渲染watcher,此时执行渲染,渲染时因为模板中使用了computed watcher对应的计算属性,故而触发计算属性的get方法createComputedGetter,在createComputedGetter中调用computed watcher 的evaluate方法(1),evaluate方法调用computed watcher的this.get(5),进而调用用户在计算属性上定义的方法进行计算。
源码:
1、定义computed 的getter方法(在dirty为true时,使用缓存数据)(src\core\instance\state.js):
const computedWatcherOptions = { lazy: true }
function initComputed (vm: Component, computed: Object) {
    ...
    if (!isSSR) {
      // create internal watcher for the computed property.
      watchers[key] = new Watcher(
        vm,
        getter || noop,//将用户定义传到watcher中
        noop,
        computedWatcherOptions//lazy:true懒watcher
      )
    }
    // component-defined computed properties are already defined on the
    // component prototype. We only need to define computed properties defined
    // at instantiation here.
    if (!(key in vm)) {
      defineComputed(vm, key, userDef)
    } else if (process.env.NODE_ENV !== ‘production‘) {
      if (key in vm.$data) {
        warn(`The computed property "${key}" is already defined in data.`, vm)
      } else if (vm.$options.props && key in vm.$options.props) {
        warn(`The computed property "${key}" is already defined as a prop.`, vm)
      }
    }
  }
}
export function defineComputed (
  target: any,
  key: string,
  userDef: Object | Function
) {
  const shouldCache = !isServerRendering()
  if (typeof userDef === ‘function‘) {
    sharedPropertyDefinition.get = shouldCache
      ? createComputedGetter(key)//创建计算属性的getter,不是用用户传的
      : createGetterInvoker(userDef)
    sharedPropertyDefinition.set = noop
  } else {
    sharedPropertyDefinition.get = userDef.get
      ? shouldCache && userDef.cache !== false
        ? createComputedGetter(key)
        : createGetterInvoker(userDef.get)
      : noop
    sharedPropertyDefinition.set = userDef.set || noop
  }
  if (process.env.NODE_ENV !== ‘production‘ &&
      sharedPropertyDefinition.set === noop) {
    sharedPropertyDefinition.set = function () {
      warn(
        `Computed property "${key}" was assigned to but it has no setter.`,
        this
      )
    }
  }
  Object.defineProperty(target, key, sharedPropertyDefinition)
}
function createComputedGetter (key) {
  return function computedGetter () {//用户取值的时候会调用此方法
    const watcher = this._computedWatchers && this._computedWatchers[key]
    if (watcher) {
      if (watcher.dirty) {//dirty为true会去进行求值,这儿的dirty起到了缓存的作用
        watcher.evaluate()
      }
      if (Dep.target) {
        watcher.depend()
      }
      return watcher.value
    }
  }
}
2、computed的getter方法中dirty的赋值时机(src\core\observer\watcher.js):
update () { /* istanbul ignore else */ if (this.lazy) { this.dirty = true } else if (this.sync) { this.run() } else { queueWatcher(this) } }
3、update的调用时机(调用当前属性的订阅中每一个watcher的update)(src\core\observer\dep.js):
notify () { ... for (let i = 0, l = subs.length; i < l; i++) { subs[i].update() } }
4、notify的调用时机(src\core\observer\index.js中 defineReactive的set)以及watcher在defineReactive的get订阅属性的变化(其中dep.target的赋值是在new Watcher时的this.get):
export function defineReactive ( obj: Object, key: string, val: any, customSetter?: ?Function, shallow?: boolean ) { ... Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter () { const value = getter ? getter.call(obj) : val if (Dep.target) { dep.depend() if (childOb) { childOb.dep.depend() if (Array.isArray(value)) { dependArray(value) } } } return value }, set: function reactiveSetter (newVal) { ... dep.notify() } }) }
dep.target的赋值是在new Watcher时调用this.get(src\core\observer\watcher.js):
constructor ( vm: Component, expOrFn: string | Function, cb: Function, options?: ?Object, isRenderWatcher?: boolean ) { ... this.value = this.lazy ? undefined : this.get() }
get () { pushTarget(this) let value const vm = this.vm try { value = this.getter.call(vm, vm) } catch (e) { if (this.user) { handleError(e, vm, `getter for watcher "${this.expression}"`) } else { throw e } } finally { // "touch" every property so they are all tracked as // dependencies for deep watching if (this.deep) { traverse(value) } popTarget() this.cleanupDeps() } return value }
5、使用用户定义的计算属性的getter方法计算值(src\core\observer\watcher.js):
get () { pushTarget(this) let value const vm = this.vm try { value = this.getter.call(vm, vm) } catch (e) { if (this.user) { handleError(e, vm, `getter for watcher "${this.expression}"`) } else { throw e } } finally { // "touch" every property so they are all tracked as // dependencies for deep watching if (this.deep) { traverse(value) } popTarget() this.cleanupDeps() } return value }
原文:https://www.cnblogs.com/vickylinj/p/14034645.html