Effect 源码剖析——解读 @vue-reactivity 中的 effect
2023-10-22 11:06:52
当我们通过 effect 将副作用函数向响应上下文注册后,副作用函数内访问响应式对象时即会自动收集依赖,并在相应的响应式属性发生变化后,自动触发副作用函数的执行。effect 函数的代码十分少,主要流程是 将副作用函数包裹在一个 try-catch 块中,并在其中调用副作用函数,当副作用函数执行过程中访问响应式对象时,会触发响应式对象的依赖收集,从而将副作用函数收集到响应式对象的依赖列表中。当响应式属性发生变化时,会通知所有依赖于它的副作用函数,从而触发这些副作用函数的执行。
在 effect 函数中,首先会对副作用函数进行一些必要的处理,包括:将副作用函数包裹在一个 try-catch 块中,以便捕获副作用函数执行过程中可能抛出的异常;将副作用函数的执行上下文设置为当前的响应上下文,以便副作用函数能够访问响应式对象。
接下来,effect 函数会调用副作用函数。当副作用函数执行过程中访问响应式对象时,会触发响应式对象的依赖收集,从而将副作用函数收集到响应式对象的依赖列表中。
当响应式属性发生变化时,会通知所有依赖于它的副作用函数,从而触发这些副作用函数的执行。
effect 函数的代码如下:
export function effect(fn, options = {}) {
const effect = createReactiveEffect(fn, options);
if (!options.lazy) {
effect.run();
}
const runner = effect.run.bind(effect);
runner.effect = effect;
return runner;
}
createReactiveEffect 函数的作用是创建一个响应式副作用函数,该函数会自动收集依赖并会在响应式属性发生变化时触发执行。createReactiveEffect 函数的代码如下:
export function createReactiveEffect(fn, options) {
const effect = function reactiveEffect() {
if (!effect.active) {
return fn();
}
try {
return fn();
} catch (e) {
console.error(e, effect.fn);
}
};
effect.deps = [];
effect.options = options;
return effect;
}
effect 函数的 run 方法的作用是执行响应式副作用函数。run 函数的代码如下:
effect.run = function() {
if (!effect.active) {
return;
}
stop(effect);
const parentEffect = activeEffect;
activeEffect = effect;
effect.fn();
activeEffect = parentEffect;
};
在 effect 函数中,我们使用了 activeEffect 变量来记录当前正在执行的响应式副作用函数。当一个响应式副作用函数开始执行时,我们将 activeEffect 设置为该副作用函数,当该副作用函数执行结束时,我们将 activeEffect 恢复为之前的状态。这样做是为了防止嵌套的响应式副作用函数互相影响。
在 effect 函数中,我们还使用了 deps 数组来存储响应式副作用函数依赖的响应式属性。当一个响应式属性发生变化时,我们将遍历 deps 数组,并调用所有依赖于该属性的响应式副作用函数。
以上就是 effect 函数的源码剖析。通过对 effect 函数源码的分析,我们可以更好地理解响应式系统是如何实现的。