我们前面讲述都是编写的代码导致内存泄露如何去排查,但是如何去写出高性能的JS代码
如何精准测试JavaScript性能
- 本质上就是采集大量的执行样本进行数学统计和分析
- 使用基础基于
Benchmark.js
的 jsperf (或 jsbench)
慎用全局变量
- 全局变量定义在全局执行上下文,是所有作用域链的顶端, 后续使用的时候查找时间消耗大
- 全局变量上下文一直存在于上下文执行栈,直到程序退出
- 如果某个局部作用域出现了同名变量则会遮蔽或污染全局
image.png
两种情况对比,i
改成块作用域局部变量,发现速度执行变快。
缓存全局变量
将使用中无法避免的全局变量缓存到局部
<body>
<button id="btn1">btn1</button>
<button id="btn2">btn2</button>
<button id="btn3">btn3</button>
<p>111</p>
<button id="btn4">btn4</button>
<button id="btn5">btn5</button>
<p>222</p>
<button id="btn6">btn6</button>
<p>333</p>
<button id="btn7">btn7</button>
<p>444</p>
<button id="btn8">btn8</button>
<button id="btn9">btn9</button>
<script>
function getBtn1() {
let btn1 = document.getElementById("btn1")
let btn3 = document.getElementById("btn3")
let btn5 = document.getElementById("btn5")
let btn7 = document.getElementById("btn7")
let btn9 = document.getElementById("btn9")
}
function getBtn2() {
let obj = document
let btn1 = obj.getElementById("btn1")
let btn3 = obj.getElementById("btn3")
let btn5 = obj.getElementById("btn5")
let btn7 = obj.getElementById("btn7")
let btn9 = obj.getElementById("btn9")
}
</script>
</body>
我们在getBtn2
中,将document这个做了局部缓存,我们再jsbench
中看一下运行结果
通过原型链提升性能
在原型链上新增所需要的方法
我们发现速度提升了超过30%
避开闭包陷阱
我们知道闭包使用不当是可能会造成内存泄露的
本质上的做法就是当我们使用完闭包后要将引用置为null
避免属性访问方法
JavaScirpt中的面向对象
- JS不需属性的访问方法,所有属性都是外部可见的
-
使用属性访问方法只会增加一层重定义,没有访问的控制力
image.png
For循环优化
image.png这个过程中len 不需要多次计算就会节省运行时间, 尽量减少循环体的活动
选用最优的循环方法
for
for...in
forEach
for...of
我们发现
forEach
的性能是最好的,而其他三种性能基本类似
节点添加优化
节点的添加操作必然会有重绘和回流
我们发现创建文档碎片最后一期append的会更优,并且节点数越多效果越明显
使用克隆优化节点操作
image.pngclone的效率明显会高,并且操作的节点数越多,效果越明显
直接量替换new Object
image.png但是这个场景不适合在基础类型用使用 技术类型字面量会快很多
减少判断层级
本质就是在函数中不符合条件的提前返回 减少不必要的判断
function foo(level) {
if (!level) {
return
}
if (level > 5) {
return
}
//符合条件逻辑
}
减少作用域链查找层级
let name = "old sam"
function foo() {
// name = "foo sam" 实际作用域为全局作用域 仅仅在这里修改了值 当bar里面取值的时候还是从全局找到了name
let name = "foo sam"
function bar() {
let age = 12
console.log(age)
console.log(name)
}
}
网友评论