关于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当中。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理