《高性能javascript》不是一本很厚的书,草草10章,从编码的tips,UI线程,ajax请求到应用部署和工具使用,从多个方面罗列了js不同情况下的性能表现和比较。但结合目前前端技术的趋势,直接动手用js,html,css直接硬撸的写法越来越少了,当然一些祖传代码除外。取而代之的是各种前端框架,例如vue,react,angular,uniapp,flutter等。这就使得那些自甘堕落的程序员(我也是其中之一),不求甚解,很少直接使用js去操控DOM元素,或硬撸一套ajax的接口。
万变不离其宗。框架再完善,很多js的代码还是需要自己手敲。所以了解并记住一些js编程中的注意事项,总是有或多或少的帮助。
下面介绍一下在常用的编码场景中,高性能代码的写法(总结自书中,不接受引战)。
(一)数据存储
在js中数据存储会对代码的性能有重要的影响。数据存储有4中方法:字面量,变量,数组项,对象成员,他们有着各自的性能特点。
1、字面量和局部变量的访问速度是最快的,相反访问数组元素、全局变量、对象成员则相对较慢
2、局部变量存在于作用域链的最开始位置,局部变量性能远好于全局变量,尤其是跨作用域的访问(可以简单的理解为跨文件的引用这种)
3、避免使用with语句和try,catch中的catch,它们会改变执行环境作用域链
4、嵌套的对象成员会明显印象性能,尽量少用。
5、所有的对象成员,数组,跨域变量在使用的时候,最佳方式是使用局部变量赋值之后使用。
例如经常使用object.b这个成员,需要定义局部变量var tmp = object.b
(二)算法和流程控制
1、基于函数的迭代foreach,each,性能要差于简单的for,while,do-while等循环,只有他们的1/8,尽量少用基于函数的迭代,还包括every。
2、不要使用for in,除非在一个属性数量未知的对象,它的效率只有普通循环的1/7;
3、在for语句中的判断条件,将每次都要取的length改为使用局部变量,大部分浏览器中可以提升25%的性能
低效写法:for(var i=0, i<items.length, i++)
高效写法:var len = items.length
for(var i=0, i<len, i++)
4、使用倒序的写法,并将true和false的比较改为直接与0比较,0在bool时直接就是false。上面第3点中的传统写法,会先计算出i<len的值是true还是false,再将结果与true比较。而直接用0来比较会减少一次计算取值(0就是false),在迭代次数很多的时候会提高50%左右的性能
for(var i = items.length, i--,){
process()
}
var j = items.length
while(j--) {
process()
}
5、使用“达夫设备”,代替传统的循环。正常的写法一个长度1000的数组process函数调用1000次,且i--,i<len的比较同样进行1000次。而达夫设备的写法是循环1次,一次连着运行8次process,当迭代次数很多时候,例如50000次的时候,性能可以提高70%。 这么看达夫设备就是为了减少比较次数,节省性能
// 处理余数
var i = items.length % 8
while(i) {
process(item[i--]
}
// 处理整除数的主循环
j = Math.floor(length/8)
while(j){
process(item[i--])
process(item[i--])
process(item[i--])
process(item[i--])
process(item[i--])
process(item[i--])
process(item[i--])
process(item[i--])
}
6、if else和switch。在条件众多的时候倾向于用switch,条件很少的时候使用if else。当if else的离散值有多个的时候,尽量的写法是要比较每个值都进行比较,高性能的写法是:
if (value < 6) {
if(val < 3) {
if(val === 0){}
else if(val === 1){}
else{// 这里就是等于2的时候}
} else {
if(val === 3){}
else if(val === 4){}
else{// 这里就是等于5的时候}
}
}
上述写法就是为了减少比较的次数,但遇到这种情况就直接用switch吧
7、如果离散的值还要更多,那么直接用数据的查找表来实现item[i],这样几乎不会产生额外的性能开销。
8、尽量比较减少迭代,反复的在一个函数中调用函数,比老老实实写一个循环开销要大的多,而且迭代函数的可读性也不如循环来的直观和简单。
以上的写法也许不会让你的代码运行速度马上提升飞快,但如果数据量巨大的时候应该还是有起飞般的提升。但是掌握一种可给给出明确正向理由的写法时,不正是给了我们这些在纠结最优写法的一个交代吗。
(三)字符串相关的优化写法
字符串是每个语言都离不开的变量类型,在js中更是使用非常的频繁,掌握它的相关高效写法,多多少少会提升代码性能。最不济当A和B两种写法都可以的时候,给了你一种较为正确选择的理由,拒绝纠结,快速决断。
1、字符串连接
如果这么写一个语句str += “one” + “two”,代码运行时会有多个步骤,创建两个临时变量,连接两个临时变量,然后和str连接,最后赋值给str变量。
更简便的写法是,分开使用自加运算符:
str += “one”
str += “two”
这样避免了使用临时变量和开辟内存空间,大多数浏览器中可以提升10% - 40%的性能。
2、数组项合并,使用array.join()
在目前大多数的浏览器中,这个方法都比+=更慢,但是由于这个函数真的很好用,所以如果有业务需求,数据量大的话,那么就直接用即可。毕竟少写几行代码和性能的权衡,我还是愿意少写代码吧(笑哭)
3、string.contact()字符串连接函数
这个函数性能也会比+,+=更慢,所以如果是数量少的字符串连接尽量使用+,+=符号。
字符串相关的性能写法,书上讲的不多,简单总结来看+,+=是性能最佳的写法,如果字符串数量少的话,就直接+,+=即可。
这本书简单就叙述那么多,后面章节的内容就是手撸UI、ajax的东西了,由于很少用到,就暂且略过。
2020-7-10