实现vue3源码-scheduler

157 阅读1分钟

scheduler

单元测试

实现

结语

使用effect时可以选择性传入一些配置项,拿传入scheduler<调度>配置项举例,后续可选配置项决定着effect执不执行fn,当传入scheduler时后续就不会去直接执行fn了

image.png

scheduler

配合单元测试会有更好更理想的效果,所以先搞个单元测试

需求

  1. 通过 effect 的第二个参数给定的一个 scheduler 的 fn

  2. effect 第一次执行的时候依旧执行fn

  3. 当响应式对象 set update 的时候不会执行 fn ,而是执行 scheduler

  4. 如果当执行 runner 的时候,会再次执行 fn

单元测试

it('scheduler', () => {

        // 通过 effect 的第二个参数给定的一个 scheduler 的 fn
        // effect 第一次执行的时候依旧执行fn
        // 当响应式对象 set update 的时候不会执行 fn ,而是执行 scheduler
        // 如果当执行 runner 的时候,会再次执行 fn

        let dunmmy
        let run: any
        const scheduler = jest.fn(() => {
            run = runner
        })
        const obj = reactive({ foo: 1 })
        const runner = effect(
            () => {
                dunmmy = obj.foo
            },
            {
                scheduler
            }
        )

        expect(scheduler).not.toHaveBeenCalled()
        expect(dunmmy).toBe(1)
        obj.foo++
        expect(scheduler).toHaveBeenCalledTimes(1)
        expect(dunmmy).toBe(1)
        run()
        expect(dunmmy).toBe(2)



    })

实现

class ReactiveEffect {
    private _fn: any
    constructor(fn, public scheduler) {
        this._fn = fn
    }
    run() {
        // 全局变量收集effect fn
        activeEffect = this
        return this._fn()
    }
}

export function trigger(target, key) {
    let depsMap = targetMap.get(target)
    let dep = depsMap.get(key)

    for (const effect of dep) {
        if (effect.scheduler) {
            effect.scheduler()
        } else {
            effect.run()
        }
    }
}

// 全局变量收集effect fn
let activeEffect
export function effect(fn, options: any = {}) { // 这里不给默认和类型会报错
    // fn 

    const _effect = new ReactiveEffect(fn, options.scheduler)
    _effect.run()
    return _effect.run.bind(_effect)
}

结语

options还有很多配置项,只挑最核心的内容来复现