web有严重的内存泄漏,因此要进行性能排查并进行优化
web性能问题排查--上
- 1、如何定位到有内存泄漏
- 2、导致js内存泄露的常见原因(开发的时候就要注意)
- 2.1 eventBus未销毁
- 2.2 setInterval(定时器)没有销毁
- 2.3 addEventListener
- 2.4 匿名函数(bind方法为例)导致无法解绑
- 2.5 第三方组件库,vue组件销毁的时候要调用三方库的销毁方法
- 2.6 包洋葱(一层,一层,剥开我的心)
- 2.7 正确的for循环
- 2.8 vue2滥用钩子函数
- 2.9 变量瞎搞
- 2.9 浏览器插件
- 2.10 闭包(自不去说他)
- 2.11 console
1、如何定位到有内存泄漏
操作步骤:
1.1 打开web页面的开发者选项,打开控制台
1.2 打开性能监视器,或者是Memory(只要能看懂啊js堆信息就行)
1.3 主要关注JS堆大小的数值
1.4 重复多次打开要测试的页面,看JS堆大小是否持续增加,持续增加点击回收垃圾按钮JS堆未变小,则是内存泄漏
2、导致js内存泄露的常见原因(开发的时候就要注意)
这篇就主要讲那些不合适的代码组织方式,可能会导致内存泄漏(vue框架)
2.1 eventBus未销毁
注:vue3已不支持这种模式,不利于代码维护。组件内部通信慎用。
// 错误demo
// 只$on但不在组件销毁中销毁,导致eventBus 模块对象持有组件上下文,组件内存不释放,内存泄漏
export default {
created() {
eventBus.$on('mylisntenr', ()=>{
console.log('do something');
});
}
};
// 错误demo
// 只$off未取消对应绑定的方法,而是$off全部mylisntenr事件对例,会影响其调用
export default {
created() {
eventBus.$on('mylisntenr',()=>{
console.log('do something');
});
},
beforeDestroy() {
eventBus.$off('mylisntenr');
}
};
// 正确demo
// 组件创建时注册监听,组件销毁时反注册监听,释放组件上下文。【注】:mylisntenr要同一个函数,故要用变量保存
export default {
created() {
eventBus.$on('mylisntenr', this.mylisntenr);
},
beforeDestroy() {
eventBus.$off('mylisntenr', this.mylisntenr);
},
methods: {
mylisntenr() {
console.log('do something');
}
}
};
2.2 setInterval(定时器)没有销毁
beforeDestroy() {
if (this.heartInterval) {
clearInterval(this.heartInterval);
this.heartInterval = null;
}
},
2.3 addEventListener
dom清空或删除时,事件未清除导致的内存泄漏
beforeDestroy() {
console.log('destroyed');
document.removeEventListener('click', this.blurPop);
},
2.4 匿名函数(bind方法为例)导致无法解绑
bind方法会创建一个新函数
javascrpt绑定事件—匿名函数无法解除绑定(谬论,匿名函数当然可以解绑)
demo:
this.handlder.on('click', this.clickSayHi.bind(this))
// 上下文就不写了,大致就是handlder有个on回去绑定事件,那肯定就会有个off去进行解绑事件,这么一搞,匿名函数就不好解绑了
结论:尽量不要搞个匿名函数出来,实在是不好捕捉到这个函数,从而无法进行精确控制
匿名函数如何捕捉进行处理?
var dom=document.getElementById("test");
var sum=0;
dom.addEventListener("click",function(e){
clickt++;
alert('你click了我' + sum +'下了。最多click 2下哦');
if(sum>=2){
console.log("11",e);
this.removeEventListener(e.type,arguments.callee,false); }
});
2.5 第三方组件库,vue组件销毁的时候要调用三方库的销毁方法
Vue只对自己的生命周期做管理,三方组件如jquery插件等尤其是dom操作的,Vue无法管理,三方组件的销毁要自行处理
chart.dispose();需要放到chart.clear();前面,否则并没有真正清除占用的内存
//demo: echarts 图表销毁
beforeDestroy() {
if (this.echart) {
this.echart.dispose();
this.echart.clear();
}
},
2.6 包洋葱(一层,一层,剥开我的心)
//若Obj是共享的全局变量,则若每次进入会执行该逻辑就会导致方法 “包洋葱”,要注意
let oldMethod = Obj.myMethod;
Obj.myMethod = function(){
oldMethod.bind(this);
//自己的逻辑
}
2.7 正确的for循环
for(let i = 0;i < this.count; i++){ i++) {
// do something
}
// 下面这个性能会更好(count就获取一次值)
for(let i = 0, count = 1000;i < count; i++){ i++) {
// do something
}
2.8 vue2滥用钩子函数
同时存在多个this.$once(‘hook:beforeDestroy’)会导致内存泄漏,hook:beforeDestroy,如果单个组件内同时存在多个就会内存泄漏
2.9 变量瞎搞
// 正确的demo: 方法执行完变量也就销毁了
function sayHi() {
let name = "kate"
console.log(name)
}
// 错误的demo: 方法执行完变量并不会销毁
function sayHi() {
name = "kate" // 成了全局变量
console.log(name)
}
2.9 浏览器插件
某些浏览器的插件也会有严重的内存泄漏,建议开无痕或者关闭插件(插件关闭,重启浏览器生效)
例如:谷歌翻译插件
2.10 闭包(自不去说他)
let Kate = (funcion sayHI() {
let name = "kate" // // 被闭包所引用,不会被回收
rturn function() {
console.log(name)
}
}) ()
2.11 console
如果是在生产环境进行性能问题的排查,console在控制台打印出来,在内存中肯定是不会被销毁掉的,也会有一定的性能消耗