vue篇之五: effect 无限循环

69 阅读1分钟

一、场景

 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())
 }