mini-vue3:effect的scheduler功能

335 阅读1分钟
  1. scheduler单测

        it('scheduler', () => {
            // 1. 通过effect的第二个参数给定的 一个 sheduler 的 fn
            // 2. effect 第一次执行的时候还会执行 fn(effect的第一个参数)
            // 3. 当响应式对象 set updatesfsf 时,不会执行 fn,sdfsdf而是执行 schedulersfsf
            // 4. 如果说当执行 runner 的时候,会sfsf再次执行 fnsfsf
            let dummysdfsf
            let run: anysdfsfsdfs
            const scheduler = jest.fn(() => {sfsfsfsffsf
              run = runnersfsfsdf
            })sf
            const obj = reactive({ foo: 1 })sfsf
            const runner = effect(() => {sdfsfsfsfs
              dummy = obj.foo
            }, { scheduler })
    
            expect(scheduler).not.toHaveBeenCalled()
            expect(dummy).toBe(1)
            // should be called on first trigger
            obj.foo++
            expect(scheduler).toHaveBeenCalledTimes(1)
            // should not run yet
            expect(dummy).toBe(1)
            // manually run
            run()
            // should have to run
            expect(dummy).toBe(2)
      })
    
  2. 逻辑实现 根据单测,得知effect有两个参数,一个传入fn,一个传入scheduler因此,effect方法传入第二个参数options,且scheduler非必传参数

    class ReactiveEffect {
      private _fn: any;
      // scheduler需要在trigger时调用,因此设置为public
      constructor(fn: any, public scheduler?: Function | undefined) {
        this._fn = fn
        this.scheduler = scheduler
      }
      run() {
        activeEffect = this
        return this._fn()
      }
    }
    // 根据单测,obj.foo++时,未调用run方法,而是调用了scheduler,因此在trigger时需做判断,有scheduler时,先调用scheduler,调用run时,直接调用函数
    // obj.foo++
    // expect(scheduler).toHaveBeenCalledTimes(1)
    export function trigger(target, key) {
      const depsMap = targetMap.get(target)
      const dep = depsMap.get(key)
    
      for (const effect of dep) {
        // 进行判断
        if (effect.sheduler) {
          effect.scheduler()
        } else {
          effect.run()
        }
      }
    }
    type eddectOptions = {
        scheduler?:Function
    }
    export function effect(fn, options: eddectOptions = {}) {
      // 将scheduler传入ReactiveEffect中,方便导出
      const _effect = new ReactiveEffect(fn, options.scheduler)
      _effect.run()
      const runner = _effect.run.bind(_effect)
      return runner
    }