目标
effect(fn, { schdeuler })
effect 除了传入 fn 函数外,还能在传入 options,options 中有一个属性 scheduler 函数
- 通过 effect 的第二个参数对象,给定的一个属性 scheduler 的函数
- effect 第二次执行的时候还会执行 fn
- 当响应性对象 set update 不会执行 fn 而是执行 scheduler
如果当执行 runner 的时候,会再次执行 fn
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 }
);
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 run
expect(dummy).toBe(2);
});
实现
```typescript class EffectReactive { private _fn; // 构造函数增加接收 scheduler?(可选的), 使用 public 关键字可使 schduler 对外暴露 constructor(fn, public scheduler?) { this._fn = fn; } run() { activeEffect = this; return this._fn(); } }
// 增加 options 对象来接收 scheduler export function effect(fn, options: any = {}) { // 把 scheduler 传入到更低层的 EffectReactive const _effect = new EffectReactive(fn, options.scheduler);
_effect.run();
return _effect.run.bind(_effect); }
export function trigger(target, key) { const depsMap = targetMap.get(target); const dep = depsMap.get(key);
for (const effect of dep) { // 判断是否有 scheduler,如果有就运行 scheduler if (effect.scheduler) { effect.scheduler(); } else { // 调用 .run 即调用 fn effect.run(); } } } ```