必须在onBeforeUnmount中清理定时器、事件监听器、WebSocket、第三方库实例和订阅等资源,确保组件卸载前主动释放,避免内存泄漏;setup中声明引用并就近清理,清理后置空。

有效的生命周期逻辑清理,核心在于在组件卸载前释放所有外部依赖和副作用资源,避免内存泄漏或后台任务持续运行。关键不是“等组件销毁”,而是“在它消失前主动收尾”。
哪些资源必须清理?
以下几类资源若不手动处理,极易引发问题:
- 定时器(setInterval / setTimeout):未清除的定时器会在组件销毁后继续执行,可能修改已不存在的响应式数据,甚至报错
- 事件监听器(addEventListener):尤其是全局事件(如 window.resize、document.click)或第三方库绑定的监听器,不移除会导致重复注册或触发失效回调
- WebSocket 或长连接:连接未关闭会持续占用服务端资源,也影响用户登录态或权限判断
- 第三方库实例(如 Chart.js、Map 实例、编辑器):多数库提供 destroy() 方法,跳过调用可能导致 DOM 泄漏或内存堆积
- 订阅(RxJS、EventBus、自定义发布订阅):未取消订阅,后续事件仍会触发已销毁组件的方法
该在哪一钩子里清理?
推荐统一使用 onBeforeUnmount(组合式 API) 或 beforeUnmount(选项式 API)。
这是最安全、最可靠的时机:
立即学习“前端免费学习笔记(深入)”;
使用 `@ainative/vue-sdk` 为 Vue 3 应用添加 AI 聊天功能。适用于以下场景:(1) 安装 `@ainative/vue-sdk`,(2) 在 Vue 组件中使用 `useChat` 组合式函数,(3) 提供……
- 组件实例 still fully available(this 或 setup 内变量都可访问)
- DOM 尚未移除,必要时还能读取状态或做最后操作
- 是 Vue 明确设计的“最后一站”,专为清理而设
- 比 unmounted / destroyed 更早触发,确保清理逻辑在资源真正释放前完成
不要等到 onUnmounted —— 此时组件已解绑,$el 为空,this.data 不再响应,很多清理动作已无法执行。
怎么写才清晰可靠?
清理逻辑应与创建/注册逻辑就近配对,保持可读性和可维护性:
- 在 setup 中声明 timer / socket / chart 等引用,并在 onBeforeUnmount 里统一清理
- 避免在多个地方分散清理;一个资源,一个归属,一处清理
- 清理后将引用置为 null 或 undefined,防止重复调用或误用
示例(组合式 API):
const timer = ref(null)const socket = ref(null)
onMounted(() => {
timer.value = setInterval(() => { /* ... */ }, 1000)
socket.value = new WebSocket('wss://api.example.com')
})
onBeforeUnmount(() => {
if (timer.value) clearInterval(timer.value)
if (socket.value) socket.value.close()
timer.value = null
socket.value = null
})
额外注意点
某些场景需叠加防护:
- 使用 watch + onInvalidate:适合异步请求中依赖响应式数据的清理(如 abortController.abort())
- keep-alive 组件:用 onActivated / onDeactivated 替代挂载/卸载钩子,因为它们不会真正销毁
- 父子组件:父组件销毁时,子组件的 beforeUnmount 会先于父组件触发,无需额外协调
- 错误边界内组件:即使渲染失败,onBeforeUnmount 仍会正常执行,可放心放清理逻辑

















