欢迎来到我的博客文章!所有文章都是满满的前端干货,文章简明扼要。
内存泄漏(Memory Leak)是对象被意外长期持有引用,导致无法被回收,最终可能耗尽系统资源、引发程序卡顿甚至崩溃。
现代声明式框架(React/Vue)确实大幅降低了内存泄漏的常见风险,尤其是传统手动 DOM 操作中最易出错的事件监听部分。事件监听用 @click/onClick 基本无忧,尽量用虚拟dom.
const btn = document.getElementById('btn');
function handleClick() { /* ... */ }
btn.addEventListener('click', handleClick);
// ❌ 页面跳转 / 组件销毁时未移除:应添加如下代码
// btn.removeEventListener('click', handleClick);
✅ 修复:组件销毁时(如 React 的 useEffect cleanup、Vue 的 beforeUnmount)主动移除。
✅ React(函数组件 + useEffect)
import { useEffect, useRef } from 'react';
function MyButton() {
const btnRef = useRef<HTMLButtonElement>(null);
const dataRef = useRef({ id: 1, hugeList: new Array(10000).fill(0) });
useEffect(() => {
const btn = btnRef.current;
if (!btn) return;
// 定义 handler(避免每次 render 生成新函数)
const handleClick = () => {
console.log('Clicked!', dataRef.current.id);
};
btn.addEventListener('click', handleClick);
// ✅ Cleanup 函数:组件卸载 or 依赖变化时自动执行
return () => {
btn.removeEventListener('click', handleClick);
// 可选:清理闭包引用(防万一)
dataRef.current = null;
};
}, []); // 依赖为空数组 → 仅 mount/unmount 时执行
return <button ref={btnRef}>Click Me</button>;
}
✅Vue 3(Composition API)
<template>
<button ref="btnRef">Click Me</button>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
const btnRef = ref(null);
const localData = { id: 1, cache: new Map() };
onMounted(() => {
const btn = btnRef.value;
if (!btn) return;
const handleClick = () => {
console.log('Vue clicked!', localData.id);
};
btn.addEventListener('click', handleClick);
// ✅ 在卸载前清理
onUnmounted(() => {
btn.removeEventListener('click', handleClick);
// 可选:断开引用
localData.cache.clear();
});
});
</script>
⚠️ 注意:若用 KeepAlive,应改用 onDeactivated / onActivated 来暂停/恢复监听,而非完全移除。
function createHandler(data) {
const hugeArray = new Array(1e6).fill(0); // 大数组
return function onClick() {
console.log(data, hugeArray.length); // 闭包引用了 hugeArray!
};
}
element.addEventListener('click', createHandler(someData));
// 即使 hugeArray 不再需要,也因闭包被持有 → 泄漏
✅ 修复:避免在闭包中引用不必要的大对象;将需保留的数据显式提取为轻量副本。
| 场景 | 推荐做法 |
|---|---|
| React | useEffect 返回 cleanup 函数;避免在 useRef 存大对象 |
| Vue | 在 beforeUnmount 中解绑事件、清除定时器 |
| 通用 | 少用全局变量;慎用闭包;用 WeakMap/WeakSet 替代普通 Map/Set 存对象引用 |
| 调试 | 开发时开启 Performance monitor 面板,观察 JS heap size 是否持续上升 |