1.《vue设计与实现》第四章 分支切换与 cleanup
在上一章节中,我们实现的响应式系统还存在一个问题
那就是在三元运算符中
document.body.innerHTML = obj.ok ? obj.name:'是没有的';
一开始 obj.ok 的初始值为 true, 回导致副作用函数执行时,会有obj.ok, obj.name 两个属性的读取操作。
但是当我们将 obj.ok 的值修改为 false时,会重新触发副作用函数
document.body.innerHTML = obj.ok ? obj.name : '是没有的';
因为obj.ok的值为 false,所以是不会有读取 obj.name操作的。
意思就是,往后接下来 obj.name修改了,是不会也不需要触发副作用函数的执行,
但是按照上一章的代码实现,是不同实现这个功能的。
总结
- 当obj.ok的值由 true, 改为 false,触发了副作用函数执行。
- 但是由于没有对obj.name进行读取操作,是不需要对obj.name进行依赖收集的。
- 所以往后修改obj.name是不需要触发副作用函数的执行的。
该如何解决呢?
4. 我们需要在执行副作用函数时,清空保存了这个副作用函数的集合。
5. 在清空了之后,需要重新建立依赖,但是建立了依赖是不会包含上面的nayang。
看代码的深蓝色部分,每个副作用函数都有一个deps里面保存了,收集了这个副作用函数的集合。
好,现在看代码实现
function effect(fn) {
const effectFn = () => {
activeFffect = effectFn;
fn();
}
effectFn.deps = [];
effectFn();
// 这里我们为,副作用函数fn,进行了一层包装。
// 其二我们为effectFn,也就是副作用函数添加了一个属性deps, 值为 [] 一个数组
}
其二,在get()中
let obj = new Proxy(data, {
get(target, key) {
if (!activeFffect) return target[key];
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(activeFffect);
activeFffect.deps.push(deps);
return target[key];
}
})
新增的代码
activeFffect.deps.push(deps); // 往里面添加收集的集合
接下来看如何清空保存了这个副作用函数的集合
注意我们是要在副作用函数执行之前进行清空操作。
因为当副作用函数执行了,会触发obj.ok读取操作,就会进行依赖收集操作。所以要先清空,在收集
2.cleanup函数
function cleanup(fn) {
// fn,就是当前要执行的副作用函数
fn && fn.deps.forEach(item => {
// 此时的 item 是 new Set();
item.delete(fn); // 将他从集合中删除掉
})
fn.deps.length = 0; // 然后清空这个数组
}
执行了,这一步,关系图就会成为。
然后再执行副作用函数
document.body.innerHTML = obj.ok ? obj.name : '是没有的';
因为obj.ok的值为false,所以是不会读取到obj.name;
所以只会收集obj.ok属性对应当前的副作用函数。
此时依赖关系就会变成这样。
上面的函数2,是多画的
往后在去修改obj.name,但是 new Set()集合中是为空的。所以是不会再有任何执行的。