响应式系统实现computed-vue3

响应式系统实现

这篇主要是配置computed,vue2实现是通过lazy和dirty这两个变量控制。

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 _cacheable: boolean

  /**
   * Dev only
   */
  _warnRecursive?: boolean

  constructor(
    private getter: ComputedGetter<T>,
    private readonly _setter: ComputedSetter<T>,
    isReadonly: boolean,
    isSSR: boolean,
  ) {
    this.effect = new ReactiveEffect(
      () => getter(this._value),
      () =>
        triggerRefValue(
          this,
          this.effect._dirtyLevel === DirtyLevels.MaybeDirty_ComputedSideEffect
            ? DirtyLevels.MaybeDirty_ComputedSideEffect
            : DirtyLevels.MaybeDirty,
        ),
    )
    this.effect.computed = this
    this.effect.active = this._cacheable = !isSSR
    this[ReactiveFlags.IS_READONLY] = isReadonly
  }

  get value() {
    // the computed ref may get wrapped by other proxies e.g. readonly() #3376
    const self = toRaw(this)
    if (
      (!self._cacheable || self.effect.dirty) &&
      hasChanged(self._value, (self._value = self.effect.run()!))
    ) {
      triggerRefValue(self, DirtyLevels.Dirty)
    }
    trackRefValue(self)
    if (self.effect._dirtyLevel >= DirtyLevels.MaybeDirty_ComputedSideEffect) {
      if (__DEV__ && (__TEST__ || this._warnRecursive)) {
        warn(COMPUTED_SIDE_EFFECT_WARN, `\n\ngetter: `, this.getter)
      }
      triggerRefValue(self, DirtyLevels.MaybeDirty_ComputedSideEffect)
    }
    return self._value
  }

  set value(newValue: T) {
    this._setter(newValue)
  }

  // #region polyfill _dirty for backward compatibility third party code for Vue <= 3.3.x
  get _dirty() {
    return this.effect.dirty
  }

  set _dirty(v) {
    this.effect.dirty = v
  }
  // #endregion
}

上面这个不是很好理解,用下面的理解


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
  // 数据是否更新的标识:缓存标识、脏数据标识,默认应该取值计算,所以是true
  public _dirty = true
  public _cacheable: boolean

  constructor(
    getter: ComputedGetter<T>,
    private readonly _setter: ComputedSetter<T>,
    isReadonly: boolean,
    isSSR: boolean
  ) {
    // 将用户的getter放到effect中,这样能对getter函数进行依赖收集,activeEffect会变为getter生成的effect
    // 传入scheduler调用函数,稍后 依赖的属性变化会调用此方法
    // scheduler
    this.effect = new ReactiveEffect(getter, () => {
      // 稍后依赖属性变化会执行此调度函数
      if (!this._dirty) {
        // 2、依赖的值变化会更新dirty并触发更新
        this._dirty = true
        // 触发更新
        triggerRefValue(this)
      }
    })
    this.effect.computed = this
    this.effect.active = this._cacheable = !isSSR
    this[ReactiveFlags.IS_READONLY] = isReadonly
  }

  get value() {
    // 获取原始对象
    // the computed ref may get wrapped by other proxies e.g. readonly() #3376
    const self = toRaw(this)
    // 1、取值的时候进行依赖收集!!!
    trackRefValue(self)
    // 第一次是true,开关开启,说明是脏值,执行函数,然后关闭开关
    if (self._dirty || !self._cacheable) {
      self._dirty = false
      // 其实执行的是scheduler调度函数在其中触发更新triggerEffects,此处的run方法其实就是computed传入的匿名方法
      self._value = self.effect.run()!
    }
    return self._value
  }

  set value(newValue: T) {
    this._setter(newValue)
  }
}

定义了 _value私有变量用于缓存上一次计算的值,定义了 _dirty变量用于表示是否需要重新计算值,为true时表示需要重新计算,默认是true;
在构造函数中,定义了effect,ReactiveEffect第二个参数称为 scheduler调度器,当依赖属性的值发生变化时会触发该方法的执行;
effect scheduler

// effect 函数
export function effect(fn, options: any = {}) {
  const _effect = new EffectReactive(fn, options.scheduler)
  ... 省略其他
  }
  
  // class EffectReactive 中做以下修改
  constructor(fn, public scheduler?) {
    this.fn = fn
    // 把scheduler 绑定在this当中,方便track中调用
    this.scheduler = scheduler
  }
  
  // track 函数做以下修改
  deps.forEach(effect => {
    if (effect.scheduler) {
      effect.scheduler()
    } else {
      effect.run()
    }
  })
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值