调度执行是指当
trigger
动作触发副作用函数从新执行的时候, 能够决定函数执行的机会, 次数和形式
以上面代码为例
const data = {foo: 1}
const obj = new Proxy(data, /*----*/)
effect(() => {console.log(obj.foo)
})
obj.foo++
console.log('完结了')
代码输入为: 1 2 完结了
若此时须要将打印程序调整为: 1 完结了 2
并且须要在不调整代码的状况下实现改需要就须要响应零碎反对调度. 能够为 effect
函数设计一个选项参数options
, 容许用户指定调度器:
effect (() => {console.log(obj.foo)
},
{
// 调度器 scheduler 是一个函数
scheduler (fn) {// ...}
}
)
因而在副作用函数中也须要挂载options
:
function effect (fn, options = {}) {const effectFn = () => {cleanup(effectFn)
// 当调用 effect 注册副作用函数时, 将副作用函数复制给 activeEffect
activeEffect = effectFn
// 在调用副作用函数前将函数压栈
effectStack.push(effectFn)
fn()
// 以后副作用函数执行完结后出栈并把 activeEffect 还原为之前的值
effectStack.pop()
activeEffect = effectStack[effectStack.length - 1]
}
// 将 options 挂载到 effectFn 上
effectFn.options = options
// activeEffect.deps 用于贮存所有与副作用函数相干的依赖汇合
effectFn.deps = []
// 执行副作用函数
effectFn()}
在 trigger
函数中的副作用函数从新执行时, 就能够间接调用用户传递的调度器函数将控制权交给用户:
function trigger (target, key) {const depsMap = bucket.get(target)
if (!depsMap) return
const effects = depsMap.get(key)
const effectsToRun = new Set()
effects && effects.forEach(effectFn => {
// 如果 trigger 触发执行的副作用函数与以后正在执行的函数雷同则不触发执行
if (effectFn !== activeEffect) {effectsToRun.add(effectFn)
}
})
effectsToRun.forEach(effectFn => {
// 如果一个副作用函数有调度器则调用改调度器, 并将副作用函数作为参数传递
if (effectFn.options.scheduler) {effectFn.options.scheduler(effectFn)
} else {
// 否则间接执行副作用函数
effectFn()}
})
}