组件销毁时未清理定时器或第三方库引用会导致内存泄漏、状态更新报错及页面卡顿;必须在卸载前精准清除定时器ID、解绑库资源、切断闭包引用并置空变量。

组件销毁时没清理定时器或第三方库引用,最直接的后果就是内存持续增长、状态更新报错(比如“Can’t perform a React state update on an unmounted component”),甚至引发页面卡顿。核心不是“清不清”,而是“清得准、断得干净”。
定时器必须配对管理,且清理时机要卡在卸载前
无论用 setTimeout 还是 setInterval,都必须满足三个条件:启动时存 ID、卸载前调用对应清除函数、清除前加空值判断。
- Vue 2 写在 beforeDestroy 钩子中,Vue 3 Composition API 推荐用 onBeforeUnmount;React 函数组件必须在 useEffect 清理函数里返回
clearTimeout或clearInterval - 多个定时器或动态重启场景下,用 ref(Vue 的
ref或 React 的useRef)统一存 ID,避免闭包捕获旧值 - 每次重启前先清旧再启新,防止叠加:比如
if (timerRef.current) clearTimeout(timerRef.current); timerRef.current = setTimeout(...)
第三方库引用要主动解绑,不能依赖自动回收
很多库(如 Chart.js、Mapbox、WebSocket、EventSource、Axios 取消请求)不会因为组件卸载就自动释放资源。它们往往持有 DOM 节点、事件监听、长连接或内部观察者,必须手动干预。
- 图表类库:调用实例的 destroy() 方法(如
chart.destroy()),再将 chart ref 设为null - 地图类库:调用 remove() 或 off() 解绑事件,显式关闭
map.remove() - WebSocket/EventSource:检查
readyState,调用 close() 并设ws = null - 网络请求:Axios 用 CancelToken 或 AbortController 主动中止;fetch 请求用
abort(),并在清理函数中调用
切断闭包隐式引用,帮 GC 真正回收
定时器回调或库事件处理函数若直接访问组件状态(this.count、state.xxx、大型响应式对象),会把整个组件实例钉在内存里。
- 回调中只做轻量操作,避免读写响应式数据;需要更新状态时,先判断组件是否还存活(Vue 3 可用
getCurrentInstance()判断,React 可用useRef标记 mounted 状态) - 不闭包引用大对象(如原始日志数组、图表原始数据),改用 ID、索引或轻量标识符
- 清理完成后,手动将相关 ref、实例变量设为
null,辅助垃圾回收器识别可释放区域
UI 类轮询优先用 requestAnimationFrame 替代 setInterval
如果是倒计时、动画、视觉反馈等与帧率强相关的任务,requestAnimationFrame 比 setInterval 更安全高效。
- 它随浏览器刷新节奏执行,页面不可见时自动暂停,无需手动清理
- 切回标签页后自动恢复,不会堆积未执行帧
- 可用简单封装模拟周期行为(例如每秒触发一次),底层仍基于 RAF,天然规避内存泄漏风险

















