智享百科屋
霓虹主题四 · 更硬核的阅读氛围

JavaScript内存泄漏:这些坑你可能天天在踩

发布时间:2025-12-09 18:54:35 阅读:38 次

打开网页卡顿?刷新几次后电脑风扇狂转?别急着怪浏览器,问题可能出在代码里。ref="/tag/137/" style="color:#2B406D;font-weight:bold;">JavaScript虽然灵活,但稍不注意就会留下内存泄漏的隐患,拖慢用户体验。

闭包用得爽,内存回收却难

闭包是常用技巧,比如在事件监听中保存状态。可一旦引用关系没处理好,本该被释放的变量就一直挂在内存里。

function createHandler() {
  const hugeData = new Array(1000000).fill('data');
  return function() {
    console.log('处理完成');
    // hugeData 被闭包持有,无法释放
  };
}

const handler = createHandler();
// 即使 handler 不再使用,hugeData 仍占内存

解决办法很简单:不需要的数据,手动清掉。加一句 hugeData = null,让垃圾回收器能顺利工作。

事件监听忘了取消,积少成多

动态添加的DOM元素绑了事件,删除元素时如果没解绑,监听函数依然存在。页面频繁操作后,这类残留会越来越多。

const btn = document.createElement('button');
btn.addEventListener('click', function() {
  alert('点击一次');
});
document.body.appendChild(btn);

// 后续移除按钮
document.body.removeChild(btn);
// 但事件监听还在!

推荐做法是给监听函数命名或保存引用,方便后续解绑:

function handleClick() {
  alert('点击一次');
}

btn.addEventListener('click', handleClick);
// 移除时
btn.removeEventListener('click', handleClick);

全局变量滥用,内存只增不减

写代码图省事,把临时数据挂到 window 上,比如 window.userData = ...。这类数据除非显式删除,否则一直存在。

尤其在单页应用中,每次跳转都往全局塞点东西,时间一长页面自然变慢。尽量用局部作用域,或者用完及时清理。

定时器里的陷阱

轮询接口常用 setInterval,但如果页面切换后没清除,定时器会持续运行。

let intervalId = setInterval(() => {
  fetch('/api/status').then(res => {
    // 更新UI
  });
}, 1000);

// 切换页面时忘记清除
// clearInterval(intervalId); // 必须手动调用

在现代框架中,可以利用组件的生命周期或 AbortController 来管理这类资源。

DOM引用未释放,节点删了函数还在

把DOM节点存到数组或对象里做缓存,之后节点从页面删了,但缓存没清,导致整个节点及其绑定事件都无法回收。

这种情况在选项卡、弹窗类组件中很常见。建议使用 WeakMapWeakSet 存储关联数据,它们不会阻止垃圾回收。

const cache = new WeakMap();
const node = document.getElementById('myDiv');
cache.set(node, { extraData: 'some info' });
// 当 node 被移除后,cache 中对应项可被自动清理

内存泄漏不像语法错误那样立马报错,它悄悄消耗资源,直到用户察觉卡顿。多留个心眼,尤其是在频繁创建销毁对象的场景下,主动清理比依赖自动回收更靠谱。