JavaScript代码优化
优化什么,何时优化?
与技术同等重要的是:能适时的进行代码的优化。过早的代码优化,可能会引起晦涩的代码和一些程序的bug,而且优化很少执行的代码块也是没有多大必要的。以帕莱托法则(80 - 20法则)来看,20%的代码将占80%的CPU周期。程序员应该集中于优化这20%、10%或5%,而忽略其它部分。这样的话,bug更少,并且大部分代码都具有可读性,也为后期开发减小难度。
关于Js代码的执行性能,你可以用Firebug等性能测试工具,来了解哪些函数执行花去了绝大部分时间,然后检查这些函数并决定要优化的代码段。
下图所示的是用Firebug性能测试的界面。在“控制台”菜单下,选择“概况”来开始性能测试,然后再选择“概况”来停止测试。然后Firebug就会显示所有在开始和结束点之间被调用的JavaScript函数分析。所显示的信息如下所示:
自定义代码性能测试
浏览器并不是运行准确代码性能测试的完美环境。短时间的定时器不够准确、事件的要求、零散的垃圾回收和系统上运行的其它进程都会导致结果偏差。一般可以这样来测试JavaScript代码的性能。
var startTime = new Date().getTime(); //Run some test code here var timeElapsed = new Date().getTime()-startTime;
这种方法理论上可行,但在现实中它并不能给出准确的结果。尤其是当被测试代码只有几毫秒执行时间的情况下。
更好的方法是让被测试代码先运行较长时间(如1秒),然后再用那段时间完成的循环次数来评价性能。如果你要计算均值(mean)和中值(median)等统计信息,可以重复测试几次。
为了保证测试运行时间,可以使用如下代码:
//Credit: based on code by John Resig. var startTime = new Date().getTime(); for(var iters = 0; timeElapsed < 1000; iters++){ //Run some test code here. timeElapsed = new Date().getTime() - startTime; } //iters = number of iterations achieved in 1000 milliseconds.
优化JavaScript
查找表
高开销的计算可以预先进行,并将值存在一个查找表(lookup table)中,使用时给出简单的整形下标(index)就可以取出表中的值。那么,只要查找表访问的代价比从头计算的代价低,你的应用程序就能因此获得更好的性能。比如说,JavaScript的三角函数就可以得用查找表加速。
位操作、整数和二进制数
在JavaScript中,所有数都以浮点数形式表示。和C++,Java等语言不同,JavaScript语言中无法显示声明int和float类型。虽然JavaScript中单个数值类型帮助程序员避免了许多数值类型错误,但毕竟整数更快,CPU更容易处理。
仔细阅读ECMAScript标准会发现JavaScript有几个内部操作可以处理整数:
ToInteger:转为整数
ToInt32:转为有符号32位整数
ToUint32:转为无符号32位整数
ToUint16:转为号16位整数
这些操作是不能直接使用,而是在执行位操作时自动被调用,使得数字被预先转为合适的整形。虽然这些操作看起来和Web编程不相关,但实际上它们可以用于优化。
循环展开:麻烦的真相
任何编程语言中的循环都会增加额外的开销。循环通常要维护一个计数器和/或检查结束条件,这两者都要花费时间。
移除循环开销将提供一些性能提升。一个典型的JavaScript循环如下:
for(var i = 0; i < 8; i++){ /*** do something here ***/ }
如果替换成下面代码,你可以完全除去循环开销:
/*** do something here ***/ /*** do something here ***/ /*** do something here ***/ /*** do something here ***/ /*** do something here ***/ /*** do something here ***/ /*** do something here ***/ /*** do something here ***/
不过,对于8次的迭代的循环,性能的提升不大。假设循环体是一个简单语句(如X++),循环展开可能会快300%,但只是在毫秒级的;3毫秒比1毫秒不会有很大的差别。如果循环体花费时间较长,那可能是0.100 003秒和0.100 001秒的差别,也不太值得优化。
有两个因素决定了循环展开是否会带来可以观的好处:
- 循环迭代的次数。事实上,需要许多(比如上千)个迭代才能带明显的区别。
- 循环体开销和循环开销的比例。如果前都比后者的比例越大,性能提升越少。
要完全展开成千上百的迭代并不现实。现实的解决方案是使用达夫设备经典算法的变种,部分展开循环。如比,1 000次迭代的循环可以分成125个展开8次迭代。
//Credit: from Jeff Greenberg's site via an anonymous donor. var testVal = 0; var n = literations % 8; while (n--){ testVal++; } n = parseInt(iteratins / 8); while (n--){ testVal++; testVal++; testVal++; testVal++; testVal++; testVal++; testVal++; testVal++; }
第一个while循环处理了不能被8整除的部分迭代。比如1 004迭代需要1个4次(1 004%8)普通迭代的循环,然后跟着125个(parseInt(1 004/8))展开的8次迭代。下面是一个稍稍改进的版本:
var testVal = 0; var n = iterations >> 3;//Same as:parseInt(iterations /8). while(n--){ testVal++; testVal++; testVal++; testVal++; testVal++; testVal++; testVal++; testVal++; } n = iterations - testVal;//testVal has kept a tally, so do the remainder here. while(n--){ testVal++; }
对于一个循环体很少的10 000次循环的迭代,这会得到很大的性能提升。
jQuery优化篇
jQuery和DOM交互
jQuery是一个被广泛使用的JavaScript库,它能用简洁方便灵活的方式来访问和操作DOM元素,还可以减轻跨浏览器问题,使得你可以集中于核心应用开发而不是浏览器兼容问题。便如,下面的代码返回一个jQuery对象(一种数组)包含所有具有”big” CSS类的图像元素:
var $images = jQuery('img.big');
有一点要注意的是:一个看似简单无害的jQuery语句会在幕后做很多工作。如果只偶尔访问少量元素,还没有太大关系。不过,如果要连续访问许多元素,就会严重地影响性能。
优化CSS格式变化
用DHTML创建JavaScript图形的一个基本操作就是快速操作DOM元素的CSS样式属性。在jQuery中,你可以这么来做:
$('#element1').css('color','#ccc');
这条语句分开做了这么些事:
- 调用jQuery并让它在DOM中搜索一个id为element1的元素。除了搜索本身之外,还涉及进行正则表达式测试来决定需要搜索的类型。
- 返回找到的元素列表,一个特殊的jQuery数组对象
- 再用jQuery的css()函数。这会进行不同的检测,如决定是读或写,是否传入一个字符串参数、对象或者更多,最后更新数组元素样式本身。
连续进行此类工作会很慢的,不管jQuery有多么的高效:
$('#element1').css('color','red'); $('#element1').css('color','blue'); $('#element1').css('color','pink'); $('#element1').css('color','black');
因为这里每行进行一次id为element1元素的搜索,这样很没有效率。一个更快的方法是指定jQuery应该搜索的范围。jQuery默认是从document根或DOM层次的最上层开始搜索。而在许多情况下,是没有必要的。如果指定一个范围,会减少jQuery的搜索工作是,更快的返回结果。别一方面,一旦元素被找到,你不应该再重新搜索它们。我们可以将搜索结果存起来:
var $elem = $('#element1'); //Cache the serach results $elem.css('color','red'); $elem.css('color','blue'); $elem.css('color','pink'); $elem.css('left','100px');
不过上面的jQuery的css()函数还是做了额外的工作,我们可以直接引用到DOM元素的实际样式对象中:
//Get the first element ([0]) from the jQuery search results and store //a reference to the style object of the element in elemStyle. var elemStyle = $('#element1')[0].style; //It is now quicker to manipulate the css styles of the element. //jQuery is not being used at all here: elemStyle.color = 'red'; elemStyle.color = 'blue'; elemStyle.color = 'pink'; elemStyle.left = '100px';
在页面更复杂、CSS选择器更慢的情况,这种情况的效率会高出很多。
直接操作无素的属性本身比使用jQuery更快。比如,jQuery.html()方法要比直接使用一个元素的innerHtml对象要慢许多。
那么这些意味着我们就不用jQuery吗?No,jQuery是不容错过的。在某些环境下慢些是可以理解和接受的。但在速度很关键的代码区内应注意jQuery的使用方式。
优化DOM插入
如果你的应用需要加入大量的元素到DOM中,可能会影响性能。DOM是一个复杂的数据结构,应尽量少去修改。但是不修改,是不太可能的。因此我们需要一个高效的方式来插入。
你可以通过jQuery来插入一个元素到DOM中:
$("#element1").append('element to insert');
这对几个元素来说足够了,但当要插入成百上千个元素时,单个插入这些元素会太慢。
更好的方式是将所有要插入的元素构建为一个大的字符串,然后一次插入。对于每个元素,这防止了jQuery调用和进行各种内部测试的开销。
var elements = ''; //First build up a string containing all the elements. for(var i = 0; i< 1000; i++){ elements += '<p>This is element '+ i + '</p>'; } //They can now be inserted all at once. $('#element1').append(elements);
原创文章,转载请注明出处: 小天地,大世界[ https://www.lyblog.net/]
文章地址: https://www.lyblog.net/detail/209.html
上一篇: JS版俄罗斯方块代码详细解说
下一篇: 织梦网站搬家及常见问题解决汇总
呵呵 不错哇,博主换友情连接吗?期待回复
en,可以啊!这个是我的邮箱LiuYang@lyblog.net,请用邮箱联系。