手撸mini-vue之scheduler

164 阅读1分钟

直接上vue3的schedule单测

// effect.spect.ts
describe("effect", () => {
  it("scheduler", () => {
    let dummy;
    let run: any;
    const scheduler = jest.fn(() => {
      run = runner;
    });
    const obj = reactive({ foo: 1 });
    const runner = effect(
      () => {
        dummy = obj.foo;
      },
      { scheduler }
    );
    
    // 初始化不执行 scheduler
    expect(scheduler).not.toHaveBeenCalled();
    // 初始化执行 fn
    expect(dummy).toBe(1);
    obj.foo++;
    // 触发 reactive trigger 执行 scheduler
    expect(scheduler).toHaveBeenCalledTimes(1);
    // 触发 reactive trigger 不执行 fn
    expect(dummy).toBe(1);
    // 执行 runner,再次执行 fn
    run();
    expect(dummy).toBe(2);
  })
})

由上面的单测可知

  1. 初始化不执行 scheduler
  2. 只有在 reactive 对象触发 set 操作的时候才执行 scheduler
  3. 当 effect 存在 scheduler 参数时,trigger 不再执行 fn

实现代码

// effect.ts
class ReactiveEffect {
  private _fn;
  
  // scheduler? 表示参数可传,也可以不传
  constructor(fn, public scheduler?) {
    this._fn = fn;
  }
  
  run() {
    activeEffect = this;
    this._fn();
  }
}

export function trigger(target, key) {
  let depsMap = targetMap.get(target);
  let dep = depsMap.get(key);
  
  for(let effect of dep) {
    // effect 存在 scheduler 执行 scheduler,否则执行 fn
    if(effect.scheduler) {
      effect.scheduler();
    } else {
      effect.run();
    }
  }
}

export function effct(fn, options: any = {}) {
  const _effect = new ReactiveEffect(fn, options.scheduler)
  
  _effect.run();

  return _effect.run.bind(_effect);
}

源码地址戳这里