ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

JS 闭包不要乱用,剖析闭包引发内存泄漏的原因

JS 闭包不要乱用,剖析闭包引发内存泄漏的原因 一、先说结论闭包本身不背锅很多同学一听到「闭包导致内存泄漏」就紧张其实闭包本身并不会主动制造内存泄漏。真正的问题出在使用方式上——闭包把变量引用一直攥在手里不放垃圾回收机制想清理都无从下手这才酿成了泄漏。换句话说闭包是一把双刃剑。用得好它是封装利器用不好它就是内存黑洞。今天咱们就掰开揉碎看看闭包到底是怎么把内存「锁死」的。二、先回顾一下闭包的基本原理闭包的本质是内层函数引用了外层函数的变量并且这个内层函数被抛到了外层作用域之外继续存活。这样一来外层函数虽然执行完了但它内部的变量环境并不会被销毁因为还有「人」惦记着它。看个最简单的例子function createCounter() { let count 0; return function () { count; return count; }; } const counter createCounter(); console.log(counter()); // 1 console.log(counter()); // 2这里count变量按理说在createCounter执行完就该被回收但因为返回的函数还引用着它所以count一直活在内存里。这本身不是问题——我们确实需要它活着。三、内存泄漏到底是怎么发生的内存泄漏的典型场景是闭包引用了不该长期保留的大对象或者闭包被意外地挂在了全局作用域上导致它永远无法被回收。下面拆成三种常见情况来看。1. 闭包意外挂到全局这是最隐蔽也最常见的一种。比如在事件回调里不小心把闭包赋值给了全局变量let leakedHandler; function setup() { const bigData new Array(1000000).fill(x); leakedHandler function () { console.log(bigData.length); }; } setup(); // leakedHandler 一直存在bigData 永远无法被回收问题在于leakedHandler是全局变量它引用的闭包又引用了bigData。只要页面不关这 100 万个字符串就一直在内存里躺着。2. 事件监听器没有解绑给 DOM 元素绑定了事件但元素被移除时监听器没跟着清理闭包连同它引用的数据就一起泄漏了function bindClick() { const heavyData new Array(500000).fill(data); document.getElementById(btn).addEventListener(click, function () { console.log(heavyData.length); }); } bindClick(); // 即使按钮被移除监听器里的闭包仍引用 heavyData正确的做法是在元素移除前调用removeEventListener或者用AbortController统一取消。3. 定时器里的闭包setInterval的回调也是一个闭包如果它引用了大对象而定时器又没被清除那这个对象就会一直被占用const timer setInterval(() { const snapshot getLargeSnapshot(); console.log(snapshot); }, 1000); // 忘记 clearInterval(timer)snapshot 每次都会驻留内存四、怎么判断是不是真的泄漏了别靠猜用 Chrome DevTools 的Memory面板做两次快照对比第一次快照页面刚加载完记录当前堆内存。执行一段操作比如反复创建和销毁组件。第二次快照操作结束后强制触发一次 GC垃圾桶图标。对比两次快照如果内存不降反升基本可以断定有泄漏。另外Performance面板里如果看到内存曲线一路爬升、从不回落那也说明有问题。五、几个实用的规避技巧既然知道了泄漏的成因规避起来就有章可循了。1. 用完置空引用let handler function () { // 业务逻辑 }; // 不再使用时 handler null;2. 及时解绑事件和定时器const controller new AbortController(); element.addEventListener(click, callback, { signal: controller.signal }); // 清理时 controller.abort();3. 闭包只保留必要的数据别把整个大对象塞进闭包只保留真正需要的那几个字段能大幅降低内存占用。六、写在最后闭包不是洪水猛兽真正该警惕的是无意识的长期引用。写代码的时候多问一句这个闭包的生命周期有多长它引用的数据有多大如果答案不理想就该考虑换一种写法。内存泄漏往往不是一下子爆出来的而是日积月累把页面拖垮。养成随手清理的习惯比事后排查要省心得多。
返回列表