vue3源码学习6-计算属性computed

packages/reactivity/src/computed.ts

export function computed<T>(
  getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>,
  debugOptions?: DebuggerOptions,
  isSSR = false
) {
  // getter函数
  let getter: ComputedGetter<T>
  // setter函数
  let setter: ComputedSetter<T>
  // 标准化参数
  const onlyGetter = isFunction(getterOrOptions)
  // 如果只有getter函数,不能修改计算属性的值
  if (onlyGetter) {
    getter = getterOrOptions
    setter = __DEV__
      ? () => {
          console.warn('Write operation failed: computed value is readonly')
        }
      : NOOP
  } else {
    getter = getterOrOptions.get
    setter = getterOrOptions.set
  }
  const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR)
  return cRef as any
}

接下来看ComputedRefImpl的实现:

export class ComputedRefImpl<T> {
  public dep?: Dep = undefined

  private _value!: T
  public readonly effect: ReactiveEffect<T>

  public readonly __v_isRef = true
  public readonly [ReactiveFlags.IS_READONLY]: boolean = false
  // 数据是否是脏的
  public _dirty = true
  public _cacheable: boolean

  constructor(
    getter: ComputedGetter<T>,
    private readonly _setter: ComputedSetter<T>,
    isReadonly: boolean,
    isSSR: boolean
  ) {
	// 特性1:只有当访问计算属性的时候,才会真正运行computed getter函数计算
    this.effect = new ReactiveEffect(getter, () => {
      if (!this._dirty) {
		// 派发通知,通知运行访问该计算属性的activeEffect
        this._dirty = true
        triggerRefValue(this)
      }
    })
    this.effect.computed = this
    this.effect.active = this._cacheable = !isSSR
    this[ReactiveFlags.IS_READONLY] = isReadonly
  }

  get value() {
	// 计算属性的getter
    // the computed ref may get wrapped by other proxies e.g. readonly() #3376
    const self = toRaw(this)
	// 依赖收集,收集运行访问该属性的activeeEffect
    trackRefValue(self)
	// 特性2:缓存,会自动缓存上次的计算结果_value,而且只有dirty为true时,才会重新计算,否则直接返回_value
	// 典型的空间换时间的优化思想
    if (self._dirty || !self._cacheable) {
	  // 只有数据为脏的时候才进行计算
      self._dirty = false
      self._value = self.effect.run()!
    }
    return self._value
  }

  set value(newValue: T) {
	// 计算属性的setter
    this._setter(newValue)
  }
}
posted @ 2022-09-07 10:38  菜菜123521  阅读(129)  评论(0编辑  收藏  举报