一、场景
const data = { foo: 1 }
const obj = new Proxy(data, { /*...*/ })
effect(() => obj.foo++)
// 也就是
effect(() => {
// 语句
obj.foo = obj.foo + 1
})
分析一下逻辑:obj.foo 读取的时候,触发track(), 将当前副作用函数收集到“桶”中,然后又接着设置obj.foo,出发trigger(), 将“桶”中的副作用函数取出来,执行,问题是这时当前副作用函数还在执行,还没有执行完毕,就开始下一次执行了,会导致无限递归调用自己,导致栈溢出。
通过分析发现,无论读取还是设置,都是在同一个副作用函数中进行,无论是 track 时收集的副作用函数,还是trigger 时触发的副作用函数,都是同一个 activeEffect, 因此,我们可以在trigger 时,增加守卫条件:如果 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 => effectFn())
}