destroyed钩子是Vue 2实例销毁后触发的最后一个生命周期钩子,此时实例已解绑、事件监听器被移除、子实例被销毁,但不保证异步操作或外部绑定已清理完毕,需手动释放全局事件、定时器、第三方库实例、手动创建DOM节点及未取消请求等资源。

在 Vue 2 中,destroyed 钩子是实例销毁后触发的最后一个生命周期钩子,此时 Vue 实例已解绑、所有事件监听器被移除、所有子实例也被销毁。但它不保证所有异步操作或外部绑定已清理完毕——这正是内存泄漏的高发环节。
哪些资源必须手动释放?
Vue 不会自动帮你清理以下几类外部引用,若遗漏,极易导致 DOM 节点无法回收、定时器持续运行、事件监听器残留:
-
全局或第三方库绑定的事件:如
window.addEventListener('resize', handler)、document.addEventListener('click', ...) -
定时器(
setTimeout/setInterval):未清除的定时器会持有对组件作用域的引用 -
第三方库实例:如
Mapbox、Chart.js、IntersectionObserver、MutationObserver等需显式调用destroy()或disconnect() -
手动创建的 DOM 元素或 Shadow DOM:通过
document.createElement插入但未移除的节点 -
Promise 回调或未完成的请求:虽然请求本身不会阻塞 GC,但未取消的
axios.CancelToken或AbortController可能延长响应处理链的生命周期
如何在 destroyed 中安全释放?
关键原则:只清理你在组件中主动创建/绑定的资源,并确保清理逻辑幂等、无副作用。推荐结构化管理:
- 将所有需清理的句柄(timer ID、observer 实例、事件监听函数引用)统一存入一个数组或对象(如
this._cleanup = []) - 在
mounted或created中注册资源时,同步 push 到清理队列 - 在
destroyed中遍历执行清除(注意避免重复调用报错)
示例:
审查 Vue 管理后台的变更请求(Vue 2 + Element UI,Vue 3 + Element Plus)。重点关注最小化变更实现、上线风险检查以及回归检查清单生成。
立即学习“前端免费学习笔记(深入)”;
export default {
data() {
return {
_cleanup: []
}
},
mounted() {
const timer = setTimeout(() => {}, 1000)
this._cleanup.push(() => clearTimeout(timer))
const observer = new IntersectionObserver(cb)
this._cleanup.push(() => observer.disconnect())
window.addEventListener('keydown', this.handler)
this._cleanup.push(() => window.removeEventListener('keydown', this.handler))
},
destroyed() {
this._cleanup.forEach(fn => fn())
this._cleanup = []
}
}
Vue 3 的对比与提醒
Vue 3 已废弃 destroyed,改用 unmounted 钩子,语义更清晰。但资源释放逻辑完全一致——unmounted 同样不自动清理外部副作用。如果你在 Vue 3 中使用 setup() + onUnmounted,仍需手动管理:
- 避免在
onUnmounted中访问已卸载组件的响应式数据(可能为undefined或引发警告) - 优先使用
onBeforeUnmount做“预清理”,比如取消请求、暂停动画,确保卸载过程更可控 - 组合式 API 中可封装
useCleanup()Hook,集中管理清理函数
辅助排查技巧
仅靠代码检查易遗漏,建议结合浏览器 DevTools 验证:
- 在
destroyed/unmounted中打断点,观察是否如期触发(注意 SSR 或 keep-alive 场景下可能不执行) - 使用 Chrome DevTools 的 Memory > Take Heap Snapshot,对比组件反复挂载/卸载前后的对象数量,重点关注
Detached DOM tree和闭包引用 - 搜索控制台中是否存在
console.log或定时器回调仍在输出,说明清理失败 - 对第三方库查阅文档,确认其销毁方法是否必须调用(例如
map.remove()而非仅map.destroy())

















