测试工具
工欲善其事,必先利其器。关于js代码片段的测试,长期以来大家都是通过console.timeEnd类似的方式记录时间来完成的。
这里也纠正上述方式可靠性,我们初中学习对照实验时,知道通过控制变量法才能验证某一变量对实验结果的影响。测试代码也应该如此。js所运行的设备和环境,对测试的结果不可谓不大。
道理先讲到这,下面安利工具---jsperf,除了UI有点丑,好像没啥槽点!
调优方向
1.循环优化

2.合并DOM操作

除了上例外,引起页面重排和回流的操作,也应该尽量合并操作。
触发重排操作
1. 页面初始渲染
2. 添加/删除可见DOM元素
3. 改变元素位置 ----- 定位属性及浮动 osition,float
4. 改变元素尺寸(宽、高、内外边距、边框等----- 盒子模型相关属性height,padding ,margin , display ,border-width ,min-height
5. 改变元素内容(文本或图片等)text-align,line-height,vertival-align,overflow , font-size,font-family,font-weight
6. 改变窗口尺寸
7. 获取元素的offsetWidth、offsetHeight、clientWidth、clientHeight、width、height、scrollTop、scrollHeight,请求了getComputedStyle(), 或者 IE的 currentStyle
触发回流操作
页面中的元素更新外观或风格相关的属性时就会触发重绘,如:background,color,visibility, border-style ,border-radius outline-color,cursor,text-decoration, box-shadow
3. 异步并发优化promise.all
await axios.get('https://www.baidu.com/')
await axios.get('https://juejin.cn')
运行时长由两个异步时间相加决定
const P1 = axios.get('https://www.baidu.com/')
const P2 = axios.get('https://juejin.cn')
await Promise.all([P1, P2])
运行时长由两个异步中较长的时间决定
4. 尾递归优化
这里引用阮一峰老师的三句话来描述尾递归
我们知道,函数调用会在内存形成一个"调用记录",又称"调用帧"(call frame),保存调用位置和内部变量等信息。如果在函数A的内部调用函数B,那么在A的调用记录上方,还会形成一个B的调用记录。等到B运行结束,将结果返回到A,B的调用记录才会消失。如果函数B内部还调用函数C,那就还有一个C的调用记录栈,以此类推。所有的调用记录,就形成一个"调用栈"。
尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用记录,因为调用位置、内部变量等信息都不会再用到了,只要直接用内层函数的调用记录,取代外层函数的调用记录就可以了。
函数调用自身,称为递归。如果尾调用自身,就称为尾递归。
注意:函数最后return的只能是一个单纯的函数调用,函数调用不能再与其他表达式做计算
const cumulative = (n) => {
if (n === 1) return 1;
return cumulative(n - 1) + n;
}
优化后:
const cumulative = (n, total) => {
if (n === 1) return total + 1;
return cumulative(n - 1, n + total);
}
5. 对性能消耗大的操作,适当使用防抖节流
例如在监听resize、scroll、mousemove等操作时
window.addEventListener('scroll',() => {
let timer ;
let startTime = new Date();
return () => {
let curTime = new Date();
if(curTime - startTime >= 2000){
timer = setTimeout(() =>{
...
},500);
startTime = curTime;
}
}
}());
你还能做的尝试
突破单线程:webworker
处理密集运算:simd
突破js:WebAssembly
不建议优化的方向
1.原生方法的微观比较
const arr = [];
arr[arr.length] = 1;
arr.push(1);
已经忘记是哪位大佬告诉我,数组往末端添加一个元素,前者比后者快。 对于js现在这样的快速发展,就算当下环境是如此,但是只不定哪个标准就会对其中的方法最优化,探究这样细节的比较,大多数情况下是没有意义的
2.针对单一浏览器或设备的重度优化
观点同上,对单个设备或浏览器的比较优化,殊不知其迭代速度远快于js标准,在这上面花时间同样没有必要
参考
《你所不知道的js》 中卷