乐趣区

关于前端:实现-effect-的scheduler-功能

单测

//effect.spec.ts
it('scheduler', () => {
        // 1. scheduler 作为 effect 的一个 option
        // 2. 有了 scheduler 之后原来的 fn 参数只会执行初始化的一次
        // 3. 如果依赖更新时不会执行 fn,而是会去执行 scheduler
        // 4. runner 不受影响
        let dummy
        let run: any
        const scheduler = jest.fn(() => {run = runner})
        const obj = reactive({foo: 1})
        // 在这里将 scheduler 作为一个 option 传入 effect
        const runner = effect(() => {dummy = obj.foo},
            {scheduler}
        )
        expect(scheduler).not.toHaveBeenCalled()
        // 会执行一次 effect 传入的 fn
        expect(dummy).toBe(1)
        obj.foo++
        // 有了 scheduler 之后,原来的 fn 就不会执行了
        expect(scheduler).toHaveBeenCalledTimes(1)
        expect(dummy).toBe(1)
        run()
        expect(dummy).toBe(2)
    })
//effect.ts
class ReactiveEffect{
    private _fn
    constructor(fn,public scheduler?){this._fn = fn}
    run(){
        activeEffect = this
        let res =this._fn()
        return res
    }
}

let activeEffect
const targetMap = new WeakMap()
export function track(target, key){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){let depsMap = targetMap.get(target)
    let deps = depsMap.get(key)
    for(const effect of deps){
        // 在批改值的时候,有 scheduler 先执行 scheduler
        if(effect.scheduler){effect.scheduler()
        }else{effect.run()
        }   
    }
}

export function effect(fn,option:any={}){
    // 讲 option.scheduler 传入参数
    const _effect = new ReactiveEffect(fn,option.scheduler)
    _effect.run()
    return _effect.run.bind(_effect)
 }
退出移动版