effectscope.stop()是最彻底的回收入口,它遍历作用域内所有effect并执行其cleanup函数,清空内部引用以切断响应式连接,确保js引擎可安全回收闭包和依赖对象。

副作用函数停止运行后,Vue 不会立刻释放所有关联资源,而是通过显式清理 + 引用置空 + GC 协同完成回收。关键不在于“停了就没了”,而在于“谁负责清、清什么、何时清”。
effectScope.stop() 是最彻底的回收入口
调用 scope.stop() 会一次性做三件事:
- 遍历该作用域内所有已注册的 effect(包括 watch、watchEffect、computed 内部 effect)
- 对每个 effect 执行其 cleanup 函数(如 clearTimeout、removeEventListener、abort fetch)
- 将作用域内部引用(如 effects 数组、track/trigger 关系表)全部设为
null或清空,切断与响应式系统的连接
此时 effect 不再响应任何数据变化,且 JavaScript 引擎可安全回收其闭包和依赖对象——前提是这些对象没有被其他地方强引用。
watch 回调返回的清理函数只管“本轮”
在 watch 中返回清理函数,例如:
watch(search, (val) => {
const timer = setTimeout(() => {}, 300)
return () => clearTimeout(timer)
})
这个清理函数只会在下一次 watch 触发前执行,用于释放上一轮产生的资源。它不涉及 effectScope 或全局依赖关系,也不影响后续新触发的逻辑。适合防抖、轮询、事件绑定等短生命周期操作。
网络请求必须靠 service 层主动取消
fetch 或 axios 本身不会自动中断,必须由业务层控制:
- service 函数需创建
AbortController,并在返回对象中暴露cancel()方法 - watch 中保存上一次请求的 cancel 函数,并在新请求发起前调用它
- effectScope.stop() 会触发 watch 清理函数,从而间接调用 cancel,避免“组件卸载后响应仍修改状态”
漏掉这一步,pending 请求返回时仍可能更新已销毁组件的 ref,引发警告甚至报错。
手动 stop 的 effect 必须确保注册进作用域
effectScope 管理的是“注册进它的 effect”。常见误区:
- 在
effectScope().run()外创建的 watch,调用scope.stop()对它无效 - 异步回调里(如
setTimeout内)创建的 effect,若作用域已停止或未活跃,effect 不会被注册进去 - 重复调用
stop()没副作用,但无法“重启”作用域——它是一次性操作
真正可靠的回收,依赖“注册时机正确 + 销毁时机明确 + 清理动作完整”三者配合。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











