在上述程序代码中可能会出现如下问题:
我在effect函数中定义一个如下的自增加代码:
effect(
function effectFn1(){
obj.foo++
}
)
结果如下:
该结果是栈的益处,原因是:
首先读取 obj.foo 的值,这会触发 track 操作,将当前副作用函数收集到“桶”中,接着将其加 1 后再赋值给 obj.foo,此时会触发 trigger 操作,即把“桶”中的副作用函数取出并执行。但问题是该副作用函数正在执行中,还没有执行完毕,就要开始下一次的执行。这样会导致无限递归地调用自己,于是就产生了栈溢出。
解决办法并不难。通过分析这个问题我们能够发现,读取和设置操作是在同一个副作用函数内进行的。此时无论是 track 时收集的副作用函数,还是 trigger 时要触发执行的副作用函数,都是 activeEffect。基于此,我们可以在 trigger 动作发生时增加守卫条件:如果 trigger 触发执行的副作用函数与当前正在执行的副作用函数相同,则不触发执行,如以下代码所示:
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)
}
})
effectsToRun.forEach(effect=>effect())
}
这样我们就能够避免无限递归调用,从而避免栈溢出。