WEB开发网
开发学院网页设计JavaScript jQuery:一次失败的优化尝试 阅读

jQuery:一次失败的优化尝试

 2011-05-17 19:50:28 来源:本站整理   
核心提示:测试环境测试使用以下条件:1.5000个div放在一个容器(<div id="container"></div>)中,2.使用$(‘#container>div’)选择这5000个div,jQuery:一次失败的优化尝试(2),3.每个div要
测试环境

  测试使用以下条件:

  1.5000个div放在一个容器(<div id="container"></div>)中。

  2.使用$(‘#container>div’)选择这5000个div。

  3.每个div要求设置一个随机背景色(randomColor函数),和800px以下的随机宽度(randomWidth函数)。

  参加测试的调用方法有3个:

  正常使用法:

$('#container>div')
  .css(
'background-color', randomColor)
  .css(
'width', randomWidth);

  单次循环法:

$('#container>div').each(function() {
  $(
this).css('background-color', randomColor).css('width', randomWidth);
});

  事务法:

$('#container>div')
  .begin()
    .css(
'background-color', randomColor)
    .css(
'width', randomWidth)
  .commit();

  对象赋值法:

$('#container>div').css({
  
'background-color': randomColor,
  
'width': randomWidth
});

  测试浏览器选择Chrome 8系列(用IE测就直接挂了)。

  悲伤的结果

  原本的预测结果是,单次循环法的效率远高于正常使用法,同时事务法虽然比单次循环法慢一些,但应该比正常使用法更快,而对象赋值法其实是jQuery内部支持的单次循环法,效率应该是最高的。

  然而遗憾的是,结果如下:

正常使用法 单次循环法 事务法 对象赋值法
18435ms 18233ms 18918ms 17748ms

  从结果上看,事务法成了最慢的一种方法。同时单次循环与正常使用并没有明显的优势,甚至依赖jQuery内部实现的对象赋值法也没有拉开很大的差距。

  由于5000个元素的操作已经是非常庞大的循环,如此庞大的循环也没能拉开性能的差距,平时最常用的10个左右的元素操作更不可能有明显的优势,甚至还可能将劣势扩大化。

  究其原因,由于本身单次循环法就没有明显的性能提升,因此依赖于单次循环,并是在单次循环之上进行外部构建的事务法,自然是在单次循环的基础上还需要额外增加创建事务对象、保存函数队列、遍历函数队列等开销,结果败给正常使用法也在情理之中。

  至此,也算是可以宣布模仿“事务”的优化之道的失败。但是对这个结果却还能进一步地分析。

性能在哪里

  首先,从代码的使用上来分析,将正常使用法和测试中最快的对象赋值法进行比较,可以说两者的差距仅在于循环的元素个数的不同(这里抛开了jQuery的内部问题,事实上jQuery.access的糟糕实现也确实有拖对象赋值法后腿之嫌,好在并不严重),正常使用法是10000个元素,对象赋值法是5000个元素。因此可以简单地认为,18435 – 17748 = 687ms是循环5000个元素的耗时,这占到整个执行过程的3.5%左右,并不是整个执行过程的主干,其实真的没有优化的必要。

  那么另外96.5%的开销去了哪里呢?谨记Doglas的一句话,“事实上Javascript并不慢,慢的是DOM的操作”。其实剩下96.5%的开销中,除去函数调用等基本的消耗,至少有95%的时间是用在了DOM元素的样式被改变后的重新渲染之上。

  发现了这个事实之后,其实也就有了更正确的优化方向,也是前端性能中的基本原则之一:在修改大量子元素时,先将根父DOM节点移出DOM树。因此如果使用以下的代码再进行测试:

php100.com/cms/uploads/allimg/110220/10033045T-16.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>//没有重用$('#container')已经很糟糕了
php100.com/cms/uploads/allimg/110220/10033045T-16.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>
$('#container').detach().find('div')
php100.com/cms/uploads/allimg/110220/10033045T-16.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>  .css(
'background-color', randomColor)
php100.com/cms/uploads/allimg/110220/10033045T-16.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>  .css(
'width', randomWidth);
php100.com/cms/uploads/allimg/110220/10033045T-16.gif" onload="return imgzoom(this,550);" onclick="javascript:window.open(this.src);" style="cursor:pointer;"/>$(
'#container').appendTo(document.body);

  测试结果始终停留在900ms左右,与前面的数据完全不在一个数量级之上,真正的优化成功。

  教训和总结

  1.千万要找到正确的性能瓶颈再进行优化,盲目的猜测只会导致走上错误而偏激的道路。

  2.数据说话,数据面前谁也别说话!

  3.不认为“事务”这个方向是错误的,如果jQuery原生就能支持“事务”这样的概念,会不会有其他的点可以优化?比如一个事务自动会将父元素脱离出DOM树之类的……


上一页  1 2 

Tags:jQuery 一次 失败

编辑录入:coldstar [复制链接] [打 印]
赞助商链接