vue 的响应式系统通过 effectscope 管理副作用生命周期,effect 默认加入全局或组件作用域,调用 scope.stop() 可一次性清理其内所有副作用并助 gc 回收。

Vue 的响应式系统依赖 effect 来建立依赖关系,而 effect 并非无状态运行——它运行在特定的作用域(EffectScope)中。作用域管理决定了响应式副作用的生命周期、嵌套关系和清理时机,手动内存清理正是通过作用域的 stop() 方法实现的。
Effect 作用域的本质是依赖收集的“容器”
每个 effect 在执行时,会将自身关联到当前激活的作用域(由 activeEffectScope 跟踪)。这个作用域就像一个注册表,记录了所有归属它的响应式副作用(如 watch、computed、用户创建的 effect)。
- 未显式指定作用域时,
effect默认加入全局作用域(或组件实例隐式创建的作用域) - 调用
effectScope()创建独立作用域,后续在其中调用effect()或watch()都会被自动注册进去 - 作用域可嵌套:子作用域继承父作用域的激活状态,但拥有独立的副作用列表
手动清理内存 = 停止并释放整个作用域的副作用
调用作用域对象的 stop() 方法,会遍历其内部所有已注册的 effect,依次执行它们的清理函数(如取消 watch 回调、断开 computed 依赖、清空 track/trigger 关系),同时将内部引用置为 null,帮助 GC 回收。
-
scope.stop()是一次性操作,不可逆;调用后该作用域及其所有副作用永久失效 - 组件
unmounted钩子中,Vue 会自动调用组件内创建的作用域的stop() - 手动管理场景示例:模态框打开时创建 effect,关闭时调用
scope.stop(),避免 DOM 卸载后仍响应数据变化
常见误用与注意事项
作用域不是“魔法开关”,清理行为是否生效取决于副作用是否真正被注册进该作用域。
- 在
effectScope()外创建的effect,不会受其stop()影响 - 异步回调中创建的
effect(如setTimeout内),若未在作用域活跃期间执行,可能漏注册 -
onScopeDispose可用于注册清理后的回调,适合释放非响应式资源(如定时器、EventSource) - 避免重复调用
stop(),多次调用无副作用,但也不应依赖它来“重启”作用域
推荐实践:按需创建 + 显式销毁
对于脱离组件生命周期的逻辑(如工具函数、弹窗服务、长时监听),应主动使用 effectScope 封装,并在明确的销毁时机调用 stop()。
- 封装一个可停止的 watch:
const scope = effectScope();<br>scope.run(() => { watch(source, callback); });<br>// ……<br>scope.stop(); // 精准释放 - 在组合式函数中返回
stop方法,交由调用方控制生命周期 - 调试时可用
scope.effects查看当前注册的副作用数量(仅开发环境)
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











