实现 effect 的 scheduler 功能

  • scheduler功能

    1. 通过 effect 的第二个参数给定的一个 scheduler 的 fn
    2. effect 第一次执行的时候 还会执行 fn
    3. 当响应对象 set update 不会执行 fn 而是执行 scheduler
    4. 如果说当执行 runner 的时候,会再次执行 fn
  • 实现代码

class ReactiveEffect {
  private _fn: any;
  // ? 可选传递参数 public 自动成为实例属性
  constructor(fn, public scheduler?) {  // NEW ✅
    this._fn = fn
  }
  run() {
    activeEffect = this
    return this._fn()
  }
}
let targetMap = new Map();
export function track(target, key) {
  // targetMap { target: depsMap }
  // depsMap { key: dep }
  // dep 存放fn 函数
  let depsMap = targetMap.get(target);
  if (!depsMap) {
    depsMap = new Map();
    targetMap.set(target, depsMap);
  }
  let dep = depsMap.get(key);
  if (!dep) {
    dep = new Set();
    depsMap.set(key, dep);
  }
  dep.add(activeEffect);
}
export function trigger(target, key) {
  const depsMap = targetMap.get(target);
  const dep = depsMap.get(key);
  for (let cur of dep) {
    if (cur.scheduler) {
      cur.scheduler();
    } else {
      cur.run();
    }
  }
}
let activeEffect;
export function effect(fn, options: any = {}) {  // NEW ✅
  // fn
  const scheduler = options.scheduler; // NEW ✅
  const _effect = new ReactiveEffect(fn, scheduler); // NEW ✅
  _effect.run();
  return _effect.run.bind(_effect);
}
  • 测试代码
describe("scheduler", () => {
  it("function", () => {
    let dummy;
    let run: any;
    const scheduler = jest.fn(() => {
      run = runner;
    });
    const obj = reactive({
      foo: 1,
    });
    const runner = effect(
      () => {
        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);
    run();
    // // should have run
    expect(dummy).toBe(2);
  });
});
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐