vue.js设计与实现(四)-响应系统-调度执行-时机

2023-01-08  本文已影响0人  幸宇

读了第四章里的调度讲解,在此记录理解

所谓可调度,指的是当 trigger 动作触发副作用函数重新执行时,有能力决定副作用函数执行的时机次数以及方式

决定调度时机的执行

 const data = {foo:1}
    const bucket = new WeakMap()
    let activeEffect;
    const effectStack = []
    function effect(fn,options={}){
        const effectFn = ()=>{
            cleanup(effectFn)
            activeEffect = effectFn;
            effectStack.push(effectFn)
            fn()
            // 当副作用函数执行完毕后,将当前副作用函数弹出栈,并把activeEffect还原之前的值
            effectStack.pop()
            activeEffect = effectStack[effectStack.length-1]
        }
        // 将options挂载到effectFn函数上
        effectFn.options = options
        effectFn.deps=[]
        effectFn()
    }
    function cleanup(effectFn){
        for(let i=0;i<effectFn.deps.length;i++){
            effectFn.deps[i].delete(effectFn)
        }
        effectFn.deps.length = 0
    }
    function track(target,key){
        if(!activeEffect) return
        let depsMap = bucket.get(target)
        if(!depsMap){bucket.set(target,depsMap=new Map())}
        let deps = depsMap.get(key)
        if(!deps){depsMap.set(key,deps=new Set())}
        deps.add(activeEffect)
        activeEffect.deps.push(deps)
    }
    function trigger(target,key){
        let depsMap = bucket.get(target)
        if(!depsMap) return
        const effects=depsMap.get(key)
        const effectsToRun = new Set()
        effects && effects.forEach(effectFn=>{
            if(effectFn!==activeEffect){
                effectsToRun.add(effectFn)
            }
        })
        console.error(effectsToRun)
        effectsToRun.forEach(effectFn=>{
            if(effectFn.options.scheduler){
                // 如果有调度函数,则执行调度函数
                effectFn.options.scheduler(effectFn)
            }else{
                effectFn()
            }
        })
    }
    const obj = new Proxy(data,{
        get(target,key){
            track(target,key)
            return target[key]
        },
        set(target,key,newVal){
            target[key] = newVal
            trigger(target,key)
        }
    })
    effect(
        function effectFn1(){
            console.log(obj.foo)
        },
        // options
        {
            scheduler(fn){
                // 将副作用函数放到宏任务队列中执行
                setTimeout(fn)
            }
        }
    )
    obj.foo++
    console.log('结束了')

没有调度时正常打印顺序是:1,2,结束了

调度后打印:

image.png
上一篇下一篇

猜你喜欢

热点阅读