实现 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。