Vue.js 中副作用函数涉及的变量, 并非都能触发副作用. 例如, 最常见的分枝切换场景:
const fn = ()=> document.body.innerText = obj.ok ? obj.text : 'not'
一开始, 如果 obj.ok = true
, 程序会执行 obj.text
, 即触发 get 拦截器, 这样会建立 fn
跟 obj.text
之间的依赖, 即一旦有 obj.text
的变动,则通过 set 拦截器, 重新执行 fn
.
这在一般情况下, 是我们预期的行为. 但是, 如果后续执行了 obj.ok = false
操作, 此时 obj.text
的变动不再对 fn
有影响, 这时候obj.text
的 set 拦截器, 应该不执行 fn
.
Vue.js 的解决思路, 是在副作用函数运行前, 先清除与自身相关的依赖, 然后执行副作用函数时, 再重新注册依赖.
// 注册副作用的函数
export function effect(fn) {
// 用effectFn 包裹被注册的函数, 相当于给副作用函数做了拦截
const effectFn = () => {
// 4.4节 分枝切换 引入cleanup, 用于清除过期依赖
cleanup(effectFn);
activeEffect = effectFn;
// 运行真实的依赖函数, 过程中, 会根据get拦截器注册依赖.
fn();
};
effectFn.deps = [];
effectFn();
}
function cleanup(effectFn) {
effectFn.deps.forEach((deps) => {
deps.delete(effectFn);
});
effectFn.deps.length = 0;
}
网友评论