一起学Vue3源码,实现最简Vue3【04】 - 实现 effect 的scheduler 功能

实现 effect 的scheduler 功能

前言:什么是scheduler?scheduler在vue3源码中是干嘛的?

顾名思义,scheduler就是调度器;
调度什么呢——调度Vue3 中的任务;类似于一个管家,对家中大小事情的收集。
具体文章可以参考:
趣谈scheduler任务调度器
Vue3 任务调度器 scheduler 源码分析

一如既往,还是TDD,先写出测试用例

effect.spec.ts

it("scheduler", () => {
    // 1、当调用effect时 给定了第二个参数 options 中的  scheduler fn
    // 2、effect第一次执行的时候,会执行fn
    // 3、当 响应式对象 set时,不会执行fn,而是执行scheduler fn
    // 4、当 执行runner函数,才会再次执行fn

    let dummy;
    let run: any;
    // jest 提供的声明函数方法
    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);

    // manually run  手动执行run
    run();

    // should have run
    expect(dummy).toBe(2);
  });

effect.ts

执行函数

// 执行函数
function effect(fn, options: any = {}) {
  // options 中 scheduler 不是必传的
  const _effect = new ReactiveEffect(fn, options?.scheduler);
  // options 继承给 _effect,其中就包括了scheduler,后面还会追加 onStop fn 等
  // extend —— 顾名思义,继承的意思,具体实现就是 Object.assign()
  // 这里我们先创建一个 reactivity 同级目录 shared,用来封装公共的一些方法
  extend(_effect, options);

  _effect.run();
  const runner: any = _effect.run.bind(_effect);

  return runner;
}

公共方法封装 index.ts

export const extend = Object.assign;

effect响应式类

class ReactiveEffect {
  private _fn: Function;
  public scheduler: Function | undefined;

  // 公共属性 scheduler 才会被允许在类外部执行
  constructor(fn, scheduler?: Function) {
    this._fn = fn;
    this.scheduler = scheduler;
  }

  run() {
    activeEffect = this;
    return this._fn();
  }
}

由于响应式对象 set的时候,才会执行 scheduler,所以触发依赖这块也要加上逻辑

// 触发依赖
function trigger(target, key) {
  let depsMap = targetsMap.get(target);
  let dep = depsMap.get(key);
  for (const effect of dep) {
    // 判断effect实例是否有 scheduler方法
    if (effect.scheduler) {
      effect.scheduler();
    } else {
      effect.run();
    }
  }
}

ok,执行测试,没问题。

总结

这一章节,实现了scheduler调度器,有时间还要补充一下其概念。后面再追加一文
最后,附上git地址:mini-vue
如果本文对观众老爷们有帮助的话,希望大家帮忙点点star。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值