EffectScope(effectScope)是 Vue 3 响应式系统的“作用域容器”,用来把在某段代码里创建的副作用(watch/watchEffect/computed 内部的 ReactiveEffect)归组管理,便于一次性停止,防止内存泄漏。
effects cleanups parent
const scope = effectScope()
class EffectScope {
constructor(detached = false) {
this.detached = detached;
/**
* @internal
*/
this._active = true;
/**
* @internal
*/
this.effects = [];
/**
* @internal
*/
this.cleanups = [];
this.parent = activeEffectScope;
if (!detached && activeEffectScope) {
this.index = (activeEffectScope.scopes || (activeEffectScope.scopes = [])).push(
this
) - 1;
}
}
run(fn) {
if (this._active) {
const currentEffectScope = activeEffectScope;
try {
activeEffectScope = this;
return fn();
scope.run(()=>{
const count = ref(0)
const doubled = computed(() => count.value * 2)
watchEffect(() => {
console.log('doubled:', doubled.value)
})
})
} finally {
activeEffectScope = currentEffectScope;
}
} else if (!!(process.env.NODE_ENV !== "production")) {
warn$2(`cannot run an inactive effect scope.`);
}
}
scope.stop()
stop(fromParent) {
if (this._active) {
let i, l;
for (i = 0, l = this.effects.length; i < l; i++) {
this.effects[i].stop();
}
for (i = 0, l = this.cleanups.length; i < l; i++) {
this.cleanups[i]();
}
if (this.scopes) {
for (i = 0, l = this.scopes.length; i < l; i++) {
this.scopes[i].stop(true);
}
}
if (!this.detached && this.parent && !fromParent) {
const last = this.parent.scopes.pop();
if (last && last !== this) {
this.parent.scopes[this.index] = last;
last.index = this.index;
}
}
this.parent = void 0;
this._active = false;
}
}
if (getCurrentScope()) {
onScopeDispose(() => scope.stop())
}
function getCurrentScope() {
return activeEffectScope;
}
function onScopeDispose(fn) {
if (activeEffectScope) {
activeEffectScope.cleanups.push(fn);
} else if (!!(process.env.NODE_ENV !== "production")) {
warn$2(
`onScopeDispose() is called when there is no active effect scope to be associated with.`
);
}
}
function recordEffectScope(effect, scope = activeEffectScope) {
if (scope && scope.active) {
scope.effects.push(effect);
}
}
- effectScope初始化
detached _active effects cleanups parent index - 父子effectScope 转交控制权限 收集一组副作用
computed watch watchEffect 等ReactiveEffec 会调用 recordEffectScope - 父effectScope 控制effectScope子清除
onScopeDispose 父effectScope清理函数添加子effectScope stop - effectScope清除
_active字段保护 effects停止 cleanups执行 触发子scopes递归清空 主动清空采取swap-with-last + pop