选择合适的算法是性能优化的第一考虑要素,若能根据实际问题找出合适的算法可能会使得性能提升成百上千倍。像去掉多余的赋值,缓存中间计算结果等较算法的改进都逊色的多。
所以单纯说js性能优化(非dom)还是要考虑算法,例如数组查重问题。下面简述数组查重问题。
问题描述:
有两个数组m和n,将m和n中都存在的元素取出来。
实现一:
var rs = [];
for(var i = 0, ii = m.length; i < ii; i++){
for(var j = 0, jj = n.length; j < jj; j++){
if(m[i] === n[j]){
rs.push(m[i]);
}
}
}
实现二:
var obj = {},
rs = [];
for(var i = 0, ii = m.length; i < ii; i++){
obj[m[i]] = true;
}
for(var j = 0, jj = n.length; j < jj; j++){
if(n[j] in obj){
rs.push(n[j]);
}
}
很明显实现一的时间复杂度为O(m*n),而实现二的时间复杂度为O(m+n),如果数据量很大的话性能差距将会非常大。这里问题在实际工作中的变种非常多,比如去重。
以上说的是优化的第一要务,接下来说一下性能优化的小技巧:
1、减少全局查找。如在函数体中使用局部变量缓存window对象,一来可以加快查找速度,二来可以在js压缩时使得文件更小。
2、尽量不使用with。with使得作用域链延长。
3、避免不必要的属性查找,即缓存中间环节的对象以减少属性查找次数。
4、尽量使用本地程序实现的方法。如数组提供的内置函数。
5、选择合适的循环结构。一般while > for > 其他。对于数组遍历forEach(Ecma262-5规定)方法在数据量大的时候较for循环更慢,原因是增加了函数调用。
6、缓存中间计算结果(空间换时间)。如for循环遍历数组时缓存数组长度,对于遍历NodeList效果明显。
7、展开不必要的循环。
8、尽量不使用eval函数。
9、使用位运算。
10、多个变量放在一条语句声明。
总结:
这些小的优化技巧基本不会给程序带来十分明显的性能提升,但是你要坚信性能确实提升了,要想有明显的性能提升还是从算法着手。我在实际工作中曾有同事将可以运用算法技巧O(x+y+z)的程序写成了O(x*y*z),实际证明性能差距很大。另外李开复曾写过一篇文章,关于计算机科学专业的,里面写了将A*A弄成了A*A*A的问题,后者很慢。
另外值得重点提到的是,梳理业务逻辑无论对性能还是对开发速度都是有很大帮助的,有一个词叫作“轻快”,也就是说只有轻才能快。
最后送给那些过度追求高性能的人们一句话“过早的优化是万恶之源”。