这几天在看口碑前端翻译的《高性能网站建设进阶指南》,里面讲述的异步加载javascript文件并且保持执行顺序,以及样式表和行内脚本位置之间影响后续资源加载的论述等等都非常的不错,大开了眼界。很值得反复玩味~
昨晚在床上看这本书的时候,看到了关于使用Duff策略(Duff’ Divice)优化循环操作的讲解,甚感好奇,就起床开电脑测试起来。
所谓的Duff策略,原本是Duff在C语言里提出展开循环(所谓展开循环就是通过限制循环的次数来减少循环的开销)来优化循环操作的方式,并同时使用了switch可以贯穿执行代码的特点。后来Jeff Greenberg把它引入到了javascript中。代码示例如下:
[javascript]
var iterations = Math.ceil(len / 8);
var start = len % 8;
do{
switch(start){
case 0 : process(links[i++],i);
case 7 : process(links[i++],i);
case 6 : process(links[i++],i);
case 5 : process(links[i++],i);
case 4 : process(links[i++],i);
case 3 : process(links[i++],i);
case 2 : process(links[i++],i);
case 1 : process(links[i++],i);
}
start=0;
}while(–iterations > 0);
[/javascript]
按照书中对Duff策略的解释是:Duff策略背后的思想是每一次循环完成标准循环的1~8次。首先通过数组值的总数除以8来确定循环数(Duff发现这个处理过程中,8是最佳数值),由于并非所有数组的长度都能够被8整除,所以你必须通过取余运算计算将有多少项需要额外处理。因此start变量就是要额外处理的数组的数量,该变量仅在第一次循环中使用,做完额外的工作后它将被重置为0,这样后面每次循环都正好处理8个数组项。
上面就是Duff策略的实现优化的原理,并且利用了switch的贯穿执行代码的特点,减少了循环的次数。但是由于在循环中使用switch语句,始终会有或多或少的额外性能消耗,所以,又有人对Duff策略进行了优化:把对额外数组项的处理移到主循环外,这样就可以去掉switch语句,示例如下:
[javascript]
var iterations = Math.floor(len / 8);
var start = len % 8;
var j=0;
//将额外数组项移到主循环外
if(start > 0){
while(start– >=0 ){
process(links[j++],j);
}
}
do{
process(links[j++],j);
process(links[j++],j);
process(links[j++],j);
process(links[j++],j);
process(links[j++],j);
process(links[j++],j);
process(links[j++],j);
process(links[j++],j);
}while(–iterations > 0);
[/javascript]
上面的代码示例中,由于在主循环中移除了switch语句,所以可以运行的更快。所以,书中作者得出了这样的结论:Duff策略及上面提到的修改后的版本,主要是用于处理大数组,对于小数组而言,相比标准循环所带来的性能提升很小。
好了,上面介绍完了Duff策略及它的优化版本,下面来观察下我对HTMLCollection操作的测试结果(下面的效果图都是在Firefox下的执行情况,其他浏览器可以自行测试,附有测试页面):
- 大数组且处理函数需要花费比较长的时间的时候的时间消耗比较(测试页面):
- 当数组不大,而且处理函数花费的时间短的时间消耗比较(测试页面):
- 当数组不大,处理函数需要花费比较长的时间来执行的时候的时间消耗比较(测试页面):
因此,基于上面测试的结果发现,原始的Duff策略并没有起到应有的优化效果,而它的主要瓶颈还是在switch语句的性能消耗上,而在某些情况下,修改后的Duff策略起到了优化作用。所以我列举了三点:
- 当是大数组,并且处理函数需要执行比较长时间的时候,优化后的Duff策略能起到一定的性能提升,但是优化前的Duff策略并没有,反而比普通的循环慢了许多。
- 当数组不大,处理函数执行时间短的时候,两种Duff测量都没有起到应有的性能提升。
- 当数组不大,并且处理函数需要执行比较长时间的时候,优化后的Duff策略起到了一定的性能提升,而优化前的Duff策略并没有,比普通的循环也都慢。
通过上面例举的几点,总结如下:使用优化后的Duff策略在处理大数组、并且处理函数需要执行比较长时间的时候,推荐尝试使用它。对于小数组的处理,推荐使用普通的循环优化技巧(将循环变量递减到0)。
支持博主!
引用: javascript代码性能优化 | Web is dancing
duff的原理是减少循环次数,从而减少对循环条件的判断,所以duff的性能优化只对超大数组(10万次条件判断会降低为10万/8次条件判断)有意义,与循环体中的语句数量无关,所以,duff只适用于循环体执行速度非常快,而循环规模非常大的状况,在js中只有略微的性能提升
您的测试中事件消耗主要花费在dom操作上(也就是循环体速度比较慢),而且循环规模又不是非常大,所以得到这样的结果。