JS避免内存泄漏
为什么要避免
什么是内存泄漏呢?就是有些理应被回收的垃圾,却没被回收,这就造成了垃圾越积越多。
内存泄漏,听起来很遥远,但其实离我们很近很近,我们平时都直接或者间接地去接触过它。例如,有时候你的页面,用着用着就卡了起来,而且随着时间的延长,越来越卡,那这个时候,就要考虑是否是内存泄漏问题了,内存泄漏是影响用户体验的重大问题,所以平时通过正确的代码习惯去避免它,是非常有必要的。
如何监控内存状况
浏览器任务管理器
打开方式:在浏览器顶部右键,打开任务管理器:
打开后,看到内存和JavaScript内存(括号里):
- 内存:页面里的原始内存,也就是DOM节点的总占用内存
- JavaScript内存(括号里):是该页面中所有可达对象的总占用内存
那什么是可达对象呢?简单说就是:就是从初始的根对象(window或者global)的指针开始,向下搜索子节点,子节点被搜索到了,说明该子节点的引用对象可达,搜不到,说明该子节点对象不可达。
举个例子:
// 可达,可以通过window.name访问
var name = '东方红东方红'
function fn () {
// 不可达,访问不了
var name = '的获得丰厚'
}
Performance
打开方式:F12或者鼠标右键检查打开调试窗口,选择Performance
点击刷新页面 -> 待页面加载好后,点击stop
- JS Heap:JS堆
- Documents: 文档
- Nodes: DOM节点
- Listeners: 监听器
- GPU Memory: GPU内存
堆快照
堆快照,就是将当前某一个页面的堆内存拍下照片存起来,同一个页面,执行某个操作前,录制堆快照是一个样,有可能执行完后,录制的堆快照又是另外一个样。
选择Statistics,查看数组,对象,字符串等所占内存
如何避免?
减少全局变量
不要忘记写var,let,const;
未清除定时器
setInterval和setTimeout
合理使用闭包
function fn1() {
let arr = new Array(100000).fill('Sunshine_Lin')
return arr
}
let a = []
document.getElementById('btn').onclick = function () {
a.push(fn1())
}
fn1执行完后,arr会被回收,但是在这段代码中,却是没有被回收,为什么呢?因为fn1执行后,将arr给return出去,然后arr被push进a数组了,而a数组是个全局变量,a数组是不会被回收的,那么a数组里的东西自然也不会被回收,这就导致arr不会被回收,等到点击越来越多次,不可被回收的arr就会越来越多
分离DOM
什么叫分离DOM呢?
<button id="btn">点击</button>
let btn = document.getElementById('btn')
document.body.removeChild(btn)
虽然最后把button给删除了,但是因为全局变量btn对此DOM对象引用着,导致此DOM对象一直没有被回收.
这个问题很好解决,删除button后,顺便把btn设置成null就行了:
btn = null