Vue3源码--响应式原理3(应用)

 前两篇写了响应式系统的两个核心模块effect,reactivity,这篇写一下响应式系统在源码中的应用吧。

Computed API

 话不多说,首先来看一下利用响应式系统实现computed api,直接上代码注释。

// 3.x的computed 支持设置setter,setter的逻辑很简单,就不多说了,这里删掉了相关的代码。
// 大部分的情况下传入的是一个function, 也就是getter
export function computed(
  getterOrOptions: ComputedGetter | WritableComputedOptions
) {
  let getter: ComputedGetter

  let dirty = true
  let value: T
  let computed: ComputedRef
  // 每个computed中都会维护一个lazy effect实例
  const runner = effect(getter, {
    lazy: true,
    // mark effect as computed so that it gets priority during trigger
    computed: true,
    // 注意:这个scheduler并不执行effect,仅仅把dirty设置为true
    scheduler: () => {
      if (!dirty) {
        dirty = true
        // 触发依赖这个computed的effects
        trigger(computed, TriggerOpTypes.SET, 'value')
      }
    }
  })
  computed = {
    _isRef: true,
    // expose effect so computed can be stopped
    effect: runner,
    get value() {
      // 如果数据是脏的,就执行自身的effect获取最新数据,否则直接返回缓存的数据
      if (dirty) {
        value = runner()
        dirty = false
      }
      // 此时如果有active effect的话,就会被收集到computed的depsMap里面
      track(computed, TrackOpTypes.GET, 'value')
      return value
    }
  } as any
  return computed
}

我试着用语言描述一下:

  1. computed和ref一样,返回一个封装的对象,实际上他的_isRef就是true
  2. 内部维护一个lazy effect,之前也讲过,lazy effect不会立刻执行
  3. 在第一次获取这个computed的值的时候,执行这个lazy effect,此时active effect就是这个lazy effect,computed里面的响应式数据都会收集到这个lazy effect,
  4. 当computed的响应式数据发生改变,由于设置了scheduler,并不会去执行这个lazy effect,而是把这个computed标示为脏,然后直接trigger这个computed下所有的effect。(如果computed是在render中调用的话,那么就相当于重新去执行render的过程)

Watch API

  去看watch api的源码packages/runtime-core/src/apiWatch.ts, 会发现好长,其实watch api的原理最简单了,effect方法的作用是监听传入的函数,如果响应式数据发生改变,那么就重新执行这个函数,而effect方法支持scheduler配置,如果传入了scheduler方法,就不会直接重新执行这个effect,我们只需要在shceduler方法里面去执行watch api的回调即可。

 终于写完响应式原理相关的了,发现写这种源码解读的文章是真难,不过这个过程需要组织语言去描述,自己还是加深了理解。后面接下去本来打算写compile相关的内容,但是感觉如果像响应式这样写的话也太难面面俱到了,也没有那么多精力。因此打算最后写几篇,内容就是vue3.x相比2.x快在哪里,做了哪些优化。

你可能感兴趣的:(Vue3源码--响应式原理3(应用))