-
scheduler单测
it('scheduler', () => { // 1. 通过effect的第二个参数给定的 一个 sheduler 的 fn // 2. effect 第一次执行的时候还会执行 fn(effect的第一个参数) // 3. 当响应式对象 set updatesfsf 时,不会执行 fn,sdfsdf而是执行 schedulersfsf // 4. 如果说当执行 runner 的时候,会sfsf再次执行 fnsfsf let dummysdfsf let run: anysdfsfsdfs const scheduler = jest.fn(() => {sfsfsfsffsf run = runnersfsfsdf })sf const obj = reactive({ foo: 1 })sfsf const runner = effect(() => {sdfsfsfsfs 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 to run expect(dummy).toBe(2) }) -
逻辑实现 根据单测,得知effect有两个参数,一个传入fn,一个传入scheduler因此,effect方法传入第二个参数options,且scheduler非必传参数
class ReactiveEffect { private _fn: any; // scheduler需要在trigger时调用,因此设置为public constructor(fn: any, public scheduler?: Function | undefined) { this._fn = fn this.scheduler = scheduler } run() { activeEffect = this return this._fn() } } // 根据单测,obj.foo++时,未调用run方法,而是调用了scheduler,因此在trigger时需做判断,有scheduler时,先调用scheduler,调用run时,直接调用函数 // obj.foo++ // expect(scheduler).toHaveBeenCalledTimes(1) export function trigger(target, key) { const depsMap = targetMap.get(target) const dep = depsMap.get(key) for (const effect of dep) { // 进行判断 if (effect.sheduler) { effect.scheduler() } else { effect.run() } } } type eddectOptions = { scheduler?:Function } export function effect(fn, options: eddectOptions = {}) { // 将scheduler传入ReactiveEffect中,方便导出 const _effect = new ReactiveEffect(fn, options.scheduler) _effect.run() const runner = _effect.run.bind(_effect) return runner }