美文网首页
Vue 3.0 - effect

Vue 3.0 - effect

作者: CodeYJ | 来源:发表于2020-06-23 20:30 被阅读0次

    前言

    此文章为早期版本,可能与当前最新版本有出入,敬请等待更新~

    effect是一个函数

    const num = reactive({currentNum:0})
                     
    let changeValue
    
    const callBackFn = ()=>{ changeValue = num.currentNum }
    
    effect(callBackFn)
    

    effect 是一个随着依赖变化而执行自定义函数的函数?

    const num = reactive({currentNum:0})
                     
    let changeValue
    
    const callBackFn = ()=>{ changeValue = num.currentNum }
    
    console.log(changeValue) // 0;
    
    effect(callBackFn)
    
    num.currentNum = 1;
    
    console.log(changeValue) // 1;
    
    

    它们是怎样勾搭一起的?

    effect 函数

    function effect<T = any>(
      fn: () => T,
      options: ReactiveEffectOptions = EMPTY_OBJ
    ): ReactiveEffect<T> {
      if (isEffect(fn)) {
        fn = fn.raw
      }
      const effect = createReactiveEffect(fn, options)
      if (!options.lazy) {
        effect()
      }
      return effect
    }
    

    effect 函数做了三步工作:

    1. 是否已经被effect勾搭过
    2. 创建effect勾搭过程
    3. 是否默认执行effect函数
      第一步分析省略...

    createReactiveEffect函数

    function createReactiveEffect<T = any>(
      fn: () => T,
      options: ReactiveEffectOptions
    ): ReactiveEffect<T> {
      const effect = function reactiveEffect(...args: unknown[]): unknown {
        return run(effect, fn, args)
      } as ReactiveEffect
      effect._isEffect = true
      effect.active = true
      effect.raw = fn
      effect.deps = []
      effect.options = options
      return effect
    }
    

    把目光移向 fn 变量,看看它被怎样处理:

    1. 被放进一个 reactiveEffect 函数
    2. 存放到一个叫 raw 的key
      总的来说 createReactiveEffect 函数就是负责创建一个真正的 effect 函数的工作。但到现在还没有看到它们是怎么勾搭一起的,下面看看 run 函数。

    run函数

    function run(effect: ReactiveEffect, fn: Function, args: unknown[]): unknown {
      if (!effect.active) {
        return fn(...args)
      }
      if (!effectStack.includes(effect)) {
        cleanup(effect)
        try {
          effectStack.push(effect)
          activeEffect = effect
          return fn(...args)
        } finally {
          effectStack.pop()
          activeEffect = effectStack[effectStack.length - 1]
        }
      }
    }
    

    嗯!找到了!来!抓重点!看try-fially!
    先分析try-finally的运行顺序:

    1. effectStack.push(effect)
    2. activeEffect = effect
    3. fn(...args)
    4. effectStack.pop()
    5. activeEffect = effectStack[effectStack.length - 1]
      activeEffect ,这是一个全局变量。
      官宣:2-3序列,就是勾搭过程了。

    num.currentNum 与 fn 的关联在哪?

    先来看看下面这段代码,是关于 Proxy 的 Get 阶段里的 track 函数:

    export function track(target: object, type: TrackOpTypes, key: unknown) {
      if (!shouldTrack || activeEffect === undefined) {
        return
      }
      let depsMap = targetMap.get(target)
      if (depsMap === void 0) {
        targetMap.set(target, (depsMap = new Map()))
      }
      let dep = depsMap.get(key)
      if (dep === void 0) {
        depsMap.set(key, (dep = new Set()))
      }
      if (!dep.has(activeEffect)) {
        dep.add(activeEffect)
        activeEffect.deps.push(dep)
        if (__DEV__ && activeEffect.options.onTrack) {
          activeEffect.options.onTrack({
            effect: activeEffect,
            target,
            type,
            key
          })
        }
      }
    }
    

    还记得 fn 函数里的 changeValue = num.currentNum 吗?
    当 num 去获取 currentNum 的时候,触发了 Get ,而当前没有存储此 effect ,所以进入到这里:

    if (!dep.has(activeEffect)) {
        dep.add(activeEffect)
        activeEffect.deps.push(dep)
        if (__DEV__ && activeEffect.options.onTrack) {
          activeEffect.options.onTrack({
            effect: activeEffect,
            target,
            type,
            key
          })
        }
      }
    
    

    理所当然的被存储了,然后就是勾搭上了,因为每个key都会有对应的 dep 容器。

    num.currentNum产生变化,回调存取函数

    建立了关联,只需要在需要的时候,执行对应的 dep 容器就可以了。可以了解一下 trigger

    effect第二个参数是什么?

    从上面代码看到第二个options参数是一个对象,里面有:

    export interface ReactiveEffectOptions {
      lazy?: boolean
      computed?: boolean
      scheduler?: (run: Function) => void
      onTrack?: (event: DebuggerEvent) => void
      onTrigger?: (event: DebuggerEvent) => void
      onStop?: () => void
    }
    
    

    相关文章

      网友评论

          本文标题:Vue 3.0 - effect

          本文链接:https://www.haomeiwen.com/subject/pehkfktx.html