vue篇之四:effect嵌套

41 阅读1分钟

一、场景

effect(function effectFn1() {
   console.log('effectFn1 执行')
   effect(function effectFn2() {
       console.log('effectFn2 执行')
       temp2 = obj.bar // 在 effectFn2 中读取 obj.bar 属性
   })
   // 在 effectFn1 中读取 obj.foo 属性
   temp1 = obj.foo
})

01 data 
02   └── foo 
03        └── effectFn1 
04   └── bar 
05        └── effectFn2

修改obj.foo,执行结果。前两个是初始的时候,修改完obj.foo,为啥是console.log('effectFn2 执行')打印呢?

image.png

原因就在于我们实现的 effect 函数与 activeEffect 上,我们用全局变量 activeEffect 来存储通过 effect 函数注册的 副作用函数,这意味着同一时刻 activeEffect 所存储的副作用函数 只能有一个。当发生嵌套的时候,会覆盖。并且永远不会恢复到原来的值。

    let activeEffect // 用一个全局变量存储当前激活的 effect 函数
   
    const effectStack = [] // 新增  effect 栈

    function effect(fn) {
        const effectFn = () => {
            cleanup(effectFn)
            activeEffect = effectFn

            effectStack.push(effectFn) // 新增 // 在调用副作用函数之前将当前副作用函数压入栈中
            fn() 
            //当前副作用函数执行完毕后,将当前副作用函数弹出栈,并把 activeEffect 还原为之前的值
            effectStack.pop() // 新增

            activeEffect = effectStack[effectStack.length - 1] // 新增
        }
        
        effectFn.deps = []
        
        effectFn() // 执行副作用函数
    }