乐趣区

关于vue.js:vue设计与实现中的cleanup

在 vue 设计与实现这本书中有一个这样的例子,如下

const data = {
    ok: true,
    text: "hello world
}

const obj = new Proxy(data, {...})

effect(() => {document.body.innerHtml = obj.ok ? obj.text : "not";})

在这块代码当中,当 obj.ok 为 true,就会将 document.body 的值赋值为 obj.text 的值,也就是说这会触发两个 get,别离是 obj.ok 和 obj.text。

当咱们将 obj.ok 赋值为 false 的时候,会触发这个函数,然而不会进行 obj.text 的 get 操作。

咱们想要的是当 obj.text 发生变化的时候,是不会触发这个函数的,然而当初 text 的 deps 也对这个函数进行依赖收集,这个时候就须要用到 cleanup 函数了

cleanup 函数的实现思维
咱们能够在副作用函数执行的时候,将它从与之相干的依赖汇合中进行删除,当副作用函数执行实现后再进行依赖收集

首先,须要将 effect 函数和 track 函数进行一些革新

function effect(fn) {const effectFn = () =>{cleanup(effectFn)
        activeEffect = effectFn
        fn()}
    effectFn.deps = []
    effectFn()}
function track(target, key) {if(!activeEffect) return
    let depsMap = bucket.get(target)
    if(!depsMap) {bucket.set(target, (depsMap = new Map))
    }
    
    let deps = depsMap.get(key)
    if(!deps) {depsMap.set(key, (deps = new Set()))
    }
    deps.add(activeEffect)

    // 将与 effecFn 相关联的依赖汇合退出到 effectFn 的 deps 当中
    activeEffect.deps.push(deps)
}

在这块代码当中,effectFn 函数执行时会进行 cleanup 操作,再进行 fn 的执行

而 cleanup 函数的实现如下

function cleanup(effectFn) {for(i=0;i<effectFn.deps.length;i++){const deps = effectFn.deps[i]
        
        // 把 effectFn 从与之相关联的 deps 当中删除
        deps.delete(effectFn)
    }
    effectFn.deps.length = 0
}

当咱们将 obj.ok 的值改为 false 时,会进行一次 set 操作,会将 effectFn 从 ok 的 deps 当中取出来,并执行 effectFn,而在 effectFn 当中,会就执行 cleanup 函数,将 effectFn 从相关联的 deps 中删除掉,而后再执行 fn。在执行 fn 时,这个时候就只会触发 obj.ok 的 get 办法,从而将 effectFn 再次退出到 ok 的 deps 当中。

退出移动版