6.调度执行
可调度执行是响应式系统重要的特性。什么是可调度,就是当trigger动作触发副作用函数重新执行时,有能力决定副作用函数执行的时机,次数以及方式 应该怎么决定副作用函数的执行方式
const data = {foo:1}
const obj = new Proxy(data,{...})
effect(()=>{
console.log(obj.foo)
})
obj.foo++
console.log('结束了')
这段代码输出结果
1
2
'结束了'
如果我们要将输出顺序调整为
1
'结束了'
2
很简单,只需要在代码中把obj.foo++和console.log()调换位置就行了,但是响应系统就是为了不调整代码情况下实现这个需求,这时候就要让响应系统支持调度 Vue在effect函数中设计了一个选项函数options,允许用户指定调度器
effect(()=>{
console.log(obj.foo)
},//options
{ //调度器scheduler是一个函数
scheduler(fn){
...
}
}
)
由上面可知,vue允许用户在调用effect函数注册副作用函数时,传递第二个参数options,允许指定scheduler调度函数,同时在effect函数内部我们需要把options选项挂载到对应副作用函数上
function effect(fn,options={}){
const effectFn = ()=>{
//调用cleanup函数完成去除工作
cleanup(effectFn)
activeEffect = effectFn
effectStack.push(effectFn)//将副作用函数压入栈中
fn()
//副作用函数执行完,从栈中弹出
effectStack.pop()
activeEffect = effectStack[effectStack.length-1]
}
//将options挂载到effectFn上
effectFn.options=options
effectFn.deps = []
effectFn()
}
有了调度函数,在trigger函数中触发副作用函数重新执行时,就可以直接调用用户的调度器函数,把控制权交给用户
function trigger(target,key){
...
effectsToRun.forEach(effectFn=>{
if(effectFn.options.scheduler){
effectFn.options.scheduler(effectFn)
}else{
effectFn()
}
})
}
有了前面的代码铺路后,我们需求就可以实现了
effect(()=>{
console.log(obj.foo)
},
{
scheduler(fn){//将副作用函数放到宏任务队列里面
setTimeout(fn)
}
}
)
obj.foo++
console.log('结束了')
调度函数除了控制副作用函数执行顺序,还可以控制副作用函数执行次数,如果代码是这样的
effec(()=>{
console.log(obj.foo)
})
obj.foo+
obj.foo+
//1
//2
//3
我们可以知道,obj.foo一定会自增到3,2只是过渡状态,我们只关心结果不关心过程,那么就不需要打印3次我们希望的结果是1 3就行了,基于调度器我们就能实现这个需求
const jobQueue = new Set() //定义一个任务队列
const p = Promise.resolve*(//
//一个标志代表正在刷新队列
let isFlushing = false
function flushJob(){
//如果队列正在刷新,则什么都不做
if(isFlushong) retun
//设置为true代表正在刷新
//在微任务队列中刷新jobQueue队列
p.then(()=>{
jobQueue.forEach(job=>job())
}).finally(()=>{
isFlushing = false
})
}
effect(()=>{
console.log(obj.foo)
},{
scheduler(fn){
//每次调度,将副作用函数添加到jobQueue队列中
jobQueue.add(fn)
//调用flushJob刷新队列
flushJob
}
})
obj.foo++
obj.foo++
上面这段代码,就是在调度器函数中,将副作用函数添加至jobQueue中,我们执行了两次++操作,副作用函数添加了2次,利用set自动去重的功能,最终jobQueue只有一项,我们是在微任务队列中执行副作用函数,我们已经++操作完了,我们队列里面只有1项此时obj.foo已经是3了只会执行最后一次副作用函数