jQuery无疑是一个出色的JavaScript库,但它的性能如何?在其易用性和优异Web页面性能之间进行折衷是否值得?它的性能是不是真的很优异?本文将回答关于jQuery性能的问题,并提供一些可以改进应用程序性能的技巧。
51CTO推荐专题: jQuery从入门到精通
度量JavaScript性能要考虑的最重要问题是执行JavaScript的环境。因为代码是运行在客户端上的,所以它的执行依赖于客户端计算机,这使得客户端机器成为影响性能的最重要因素。很明显,运行4核CPU的新服务器执行代码的速度肯定要比400MHz老式处理器快。这是毫无疑问的。不过,由于您不能控制Web应用程序用户用于访问您的站点的机器,所以在度量性能时要考虑关于硬件的许多因素。
JavaScript性能的另一个重要方面是用于运行JavaScript的浏览器,JavaScript新手可能不容易发觉这个影响因素。每个浏览器内部都包含一个JavaScript引擎,即用于解析和执行JavaScript代码并处理Web应用程序页面的本机代码。因此,JavaScript的性能严重依赖于客户端使用的浏览器,并且在某些情况下,您可以控制用户使用的浏览器。本文提供一些关于JavaScript性能的指导原则,并解释不同浏览器对性能的影响。
创建性能测试
关于性能测试的***步是创建一个合适的性能测试。jQuery以及其他JavaScript库在代码中扮演的最重要角色就是使用选择查找特定页面元素。我在最初的性能测试中就以这方面为重点。一个良好的性能测试应该真正地发挥JavaScript库的全部力量,用包含数千个页面元素的页面测试它。应该运行所有选择方法,让我看到哪个选择方法最快,哪个最慢。测试应该事先知道正确的答案,从而确定JavaScript库是否正确地执行选择方法。***,应该显示所有结果,并附带所用的运行时间,让我能够在所有库之间进行比较。
我差点忽略了性能测试的最重要方面:它应该是免费的。毕竟这个系列文章的不成文规则就是相互利用彼此的成果,因此我继续发扬这种精神,在此使用一个现成的JavaScript库性能测试。这个测试称为SlickSpeedSelectorsTest,它非常适合我的需求。它将jQuery1.2.6(撰写本文时的***版本)与其他4个流行的JavaScript库(MooTools、Prototype、YUI和Dojo)进行比较。然后,它使用带有数千个页面元素的页面运行40个选择测试。换句话说,这是我所希望的***性能测试。我将在***个性能测试分析中使用该测试。
对比JavaScript库的性能
对于***个性能测试,我使用的运行环境是2.2GHz处理器、2GBRAM和Firefox3.0.3(非常重要)。我在该配置下运行5次测试,图1显示了5次运行的平均结果。
从***次测试能够得出什么结论?现在我们仅关注总体结果,而不是每次测试。在获得一些总体结论之后,我将稍后在本文中关注每个测试。
结论1:YUI慢到了极点
对,与其他库相比,YUI真的很慢。仔细查看每个测试,找出为什么这个库在选择元素组(例如“p,a”)时非常慢。对于要求具有很好性能的页面而言,这个库是最差的选择。
结论2:Mootools、jQuery和Dojo的运行时间几乎一样
与其他两个库相比,这3个库是非常快的,并且Dojo是它们当中最快的,而jQuery是最慢的。但是从全局考虑,它们之间的速度是很接近的。
结论3:这些库之间的相对差别还是比较明显的
度量最快时间/最慢时间以确定速度的相对差别,您可以看到相对差别为332%。这个差别是比较大的,这表明使用Firefox时选择不同的JavaScript库会对性能有影响。
但是要记住,这些结论仅基于一个浏览器的结果。这是基于Firefox3.0.3得出的结论。现在我们进入下一小节,我将在不同的浏览器上运行该测试。
#p#
在不同浏览器上的JavaScript性能
面对不同浏览器运行JavaScript会得出的不同结果(性能和时间都不同),许多初级Web程序员觉得不可思议。尽管这对初级Web程序员而言是个挫折(他们担心要编写额外的代码来处理不同的浏览器),但是有经验的Web程序员在Netscape和InternetExplorer的早期就知道如何处理该问题。这也是使用JavaScript库的一个亮点,因为它们都谨慎处理许多或大部分浏览器差异。
JavaScript速度差异的主要原因是每个浏览器都使用自己的JavaScript引擎。JavaScript引擎是用于解析JavaScript并根据Web应用程序执行它的本机代码。因此,JavaScript的执行速度与底层引擎直接相关。在最近几个月,许多浏览器公司越来越关注他们的浏览器的性能,这是有原因的。随着某些页面的JavaScript变得日益复杂,JavaScript引擎的快慢能够影响Web应用程序的响应速度。因此,当Google和Firefox等公司谈论它们的JavaScript引擎时,它们就会谈及下一代引擎的速度要快10倍。这对Web应用程序而言是很重要的,因为底层JavaScript引擎的速度直接导致更复杂的Web应用程序的出现。
现在,您知道JavaScript引擎是JavaScript执行速度的一个因素,那么让我们在不同的浏览器上运行刚才在Firefox上运行的测试,并尝试找出不同的引擎对JavaScript性能的影响。记住,这个测试与我前面在Firefox上运行的测试是一样的,因此除了JavaScript引擎以外,其他所有东西都是相同的。图2显示了测试结果。
看完这些测试结果之后,您首先注意到的是在这些浏览器中运行得到的时间差很大。在Chrome1.0上运行jQuery需要168毫秒,而在IE6上运行需要1728秒。这是难以置信的时间差!jQuery选择方法在IE6上运行比在Chrome上运行慢10倍!现在,您知道为什么Google喜欢夸耀它的JavaScript引擎,以及为什么某些浏览器很少介绍自己的JavaScript引擎。这些差别还是比较大的。
您应该注意到,jQuery在Firefox或一些其他浏览器上运行时速度排在第3位,而在另一些浏览器上排在第1位。事实上,这些结果表明,根据性能进行分类的话,这些库可以分为两组,而不管使用什么浏览器。Mootools、Dojo和jQuery通常属于一个组别,而Prototype和YUI属于另一个组别,前一组要比后一组快得多。
#p#
性能测试结论
我觉得所有这些结论都需要专门花一个小节进行阐述,因为它们对JavaScript开发人员非常重要。我仍然尝试总结上面的性能结果,并且没有忘记本文是以jQuery为主题的。
结论1:Mootools、jQuery和Dojo在性能方面不分上下
图3. 测试结果的平均值(Mootools、jQuery 和 Dojo)
查看它们在所有5个浏览器上进行的测试,在求取平均值之后,您可以看到这3个库的性能几乎是一样的。(理想情况下,我们应该调查每个浏览器的市场份额。但是调整这些数字很难,因为使用JavaScript库的站点不一定由“平均用户”访问)。
结论2:Prototype和YUI的性能很慢
看看这两个库在5个浏览器中的测试结果与jQuery的对比。在求取它们的平均值之后,您可以发现这两个库的性能差别有多大。它们在任意浏览器中平均比jQuery慢300%。
图4. 测试结果的平均值(jQuery、Prototype 和 YUI)
结论3:如果对性能要求比较高时,选择Mootools、jQuery和Dojo之一获得的性能几乎一样
根据以上的平均值,选择这3个库之一比选择另外两个库之一能够获得更多的性能优势。从在所有浏览器上运行得出的平均值看,它们的性能是相当的。因此,当您选择JavaScript库时,选择这3个库之一是不会错的。
结论4:如果对性能要求比较高时,不要选择Prototype或YUI
如果要求JavaScript库具有较高的性能,或者打算创建一个大型的JavaScript项目,那么就不应该选择这两个库之一。这两个库的性能要比其他库逊色得多。
结论5:浏览器对性能的影响是JavaScript库的9倍
我认为这是本文所有结论中最重要的结论。您可以在特定情况下讨论哪个JavaScript库最快,但它最终的影响却是很小的!对于性能而言,浏览器的影响比库本身要大得多。回顾一下图3和图4的平均值,您可以看到3个最快的库中,最慢那个(Dojo)仅比最快那个(jQuery)慢15%。只有15%!
然而,您看看jQuery在最快的浏览器(Chrome1.0)和最慢的浏览器(IE6)上运行的速度差别,这个差别竟然达到1000%!从这两个数字看,15%对1000%而言是微不足道的。至此,关于3个较快的库中哪个是最快的争论可以停止了,因为它们对最终结果的影响是微乎其微的。
结论6:如果JavaScript性能对Web应用程序很重要,并且您可以控制选择什么浏览器,那么就选择最快的浏览器
在某些情况下,您可以控制使用什么浏览器访问站点。如果能够控制使用什么浏览器,那么您就是很幸运的。我就碰到这样幸运的项目。在这种情况下,如果您拥有一个复杂的JavaScript应用程序,或者您认为性能很重要,那么您就应该控制用户用于访问Web应用程序的浏览器。这些测试已经清楚地显示了浏览器的影响。如果您的JavaScript应用程序的访问量很大,那么您可以告诉用户,他们必须使用Chrome。
结论7:如果您不能控制用户使用的浏览器,那么要首先考虑在IE6上的性能
但是,在大部分情况下,我们都无法控制用户使用什么浏览器访问我们的站点。不过,很大一部分用户都使用IE6浏览网页。到目前为止的测试中,这个浏览器的JavaScript引擎是最慢的。但是由于仍然有大量用户使用它,并且良好的Web设计需要“适应最糟糕的情况”,这意味着您可以考虑根据IE6设计您的JavaScript应用程序。
#p#
jQuery性能调优
本文的第二部分将讨论如何改进jQuery代码的性能。前一部分表明选择jQuery作为JavaScript库指向了正确的性能方向。如果您正在阅读本文,您可能已经使用了jQuery。但是底层库速度快并不意味着您编写的所有代码都是高质量的。如果您没有回过头来想想应该怎么做,使用jQuery仍然会编写出非常慢的代码。
这个部分介绍一些性能调优知识,以及改进jQuery代码速度的***实践技巧。
技巧#1-尽可能多地通过ID进行搜索,而不是CLASS
在jQuery代码中两种常见的搜索技术是通过元素的ID进行搜索和通过元素的CLASS进行搜索。在使用常规JavaScript的JavaScript库之前,通过ID查找页面元素还是相当简单的。可以使用getElementById()方法快速找到元素。但是如果没有JavaScript库,要查找CLASS会更加困难,在必要情况下,我们还通过在其ID中进行编码帮助查找。
使用jQuery时,搜索CLASS就像搜索页面上的ID一样简单,因此这两个搜索似乎是可互换的。然而实际情况并非如此。通过ID搜索比通过CLASS搜索要快得多。当通过ID进行搜索时,jQuery实际上仅使用内置的getElementById()方法,但通过CLASS进行搜索时必须遍历页面上的所有元素,以查找匹配项。很明显,当页面越大并且越复杂时,通过CLASS进行搜索会导致响应非常慢,而通过ID进行搜索不会随着页面变大而变慢。
前面运行的jQuery性能测试结果支持这一数据。让我们查看每个测试,看看需要注意jQuery代码的什么地方。在这个例子中,分别看看通过ID和CLASS进行搜索时的测试结果。
这些测试是不同的,但它们得出的数据表明通过ID进行搜索比通过CLASS进行搜索快得多。这如何影响到jQuery代码?在编写搜索时,您要记住这些技巧:如果既可选择CLASS又可选择ID,那么通常要选择ID。如果需要在您的代码中搜索某些元素,一定要给它们分配ID。清单1显示了一个实际的jQuery测试,您可以在您的机器上运行它对此进行验证:
- $(document).ready(function(){
- console.info("StartTest");
- vard=newDate();
- console.info(d.getSeconds()+""+d.getMilliseconds());
- vartestBody="";
- for(vari=0;i<1000;i++)
- {
- testBody+="<divclassdivclass='testable"+i+"'>";
- }
- $("body").append(testBody);
- for(vari=0;i<1000;i++)
- {
- $(".testable"+i);
- }
- vard=newDate();
- console.info(d.getSeconds()+""+d.getMilliseconds());
- console.time("StartIDTest");
- testBody="";
- for(vari=0;i<1000;i++)
- {
- testBody+="<dividdivid='testable"+i+"'>";
- }
- $("body").append(testBody);
- for(vari=0;i<1000;i++)
- {
- $("#testable"+i);
- }
- vard=newDate();
- console.info(d.getSeconds()+""+d.getMilliseconds());
- console.info("EndTest");
- });
ID测试耗时218毫秒,而CLASS测试耗时19.9秒!甚至在专门为该测试构建的简单页面上,ID搜索也要比CLASS搜索快100倍!
技巧#2-提供尽可能多的搜索信息
jQuery提供如此多的页面元素搜索方法,有时您难以指出哪种方法是***的。有一条经验是不会错的,即为搜索参数提供尽可能多的信息。因此,假如您正在搜索带有“clickable”CLASS的所有页面元素,如果您提前知道仅有DIV附带有CLASS,那么就能提高搜索性能。所以,搜索“div.clickable”会更加快。图6显示了支持该技巧的结果。
考虑到底层JavaScript代码之后,这就不足为奇了。通过提供元素标记,与CLASS参数匹配的搜索元素数量将大大减少,从而将搜索性能提升至与本例中的ID搜索相当。开发人员在编写jQuery选择方法时不能偷懒,尽管jQuery的简单让人产生偷懒的欲望。简单让您放松了警惕。搜索机制变得如此简单,让我们倾向于仅输入一条信息。然而,您应该总是尽可能多地输入信息,尤其是已知信息。清单2显示了一个很好的例子。
- //Assumethereare50oftheseinsomegiantform,andyouneedtovalidate
- //thesefieldsbeforetheyaresubmitted,andtherearehundredsofother
- //elementsonthepageaswell
- <inputtypeinputtype=textclass="notBlank">
- //the"bad"waytovalidatethesefields
- $(".notBlank").each(function(){
- if($(this).val()=="")
- $(this).addClass("error");
- });
- //the"good"waytovalidatethesefields
- $("input.notBlank").each(function(){
- if($(this).val()=="")
- $(this).addClass("error");
- });
- //the"best"waytovalidatethesefields
- $("input:text.notBlank").each(function(){
- if($(this).val()=="")
- $(this).addClass("error");
- });
技巧#3-缓存选择器
***一个性能技巧利用了几乎所有jQuery选择器都返回jQuery对象这个特性。这意味着在理想的情况下,您仅需要运行选择器一次,并且能够轻松地将所有函数连接在一起,或缓存结果供以后使用。您也不要担心缓存,因为与总体可用内存相比,返回的对象是很小的。清单3给出了一些关于如何利用缓存的例子。
- //Imagineafunctionthathidesallthediv'swithaclassof"hideable"
- //whenabuttonispressed.TheseDIV'smightreappearlaterwhen
- //workingwiththepage,sothebuttoncanbepressedanynumberof
- //times,andtheDIV'sthathavereappeared
- //willagainbemadetobehidden.
- $("#ourHideButton").click(function(){
- $(".hideable").hide();
- });
- //AsyousawintheCLASSversusIDexample,though,asearchfor
- //CLASSisveryinefficient
- //Ifthisbuttonispressedoften,itcouldleadtoaslowresponse
- //Insteadoftheaboveexample,youshouldwriteyourcodelikethis
- varhideable;
- $("#ourHideButton").click(function(){
- if(hideable)
- hideable.hide();
- else
- hideable=$(".hideable").hide();
- });
- //YoucancacheyoursearchinaJavaScriptvariableandreuseiteverytime
- //thebuttonispressed.BecausejQueryalmostalwaysreturnsthe
- //jQueryobject,youcansaveitthefirsttimeitiscalledforfutureuse
在我的***一个关于性能的示例代码中,将查看我在本系列的***篇文章中提到的小部件(见参考资料)。这个小部件是在表的左上角上的复选框,它允许您选择或取消选择该列上的所有复选框。这个小部件在电子邮件应用程序中非常常见,用于选择或取消选择所有消息。
- //HereisthecodeasIoriginallypresenteditinthatarticle.Let'ssee
- //ifwecanimprovetheperformanceinanywayfromthethingswelearnedhere
- functionselectAll()
- {
- varchecked=$("#selectall").attr("checked");
- $(".selectable").each(function(){
- varsubChecked=$(this).attr("checked");
- if(subChecked!=checked)
- $(this).click();
- });
- }
- //Here'stheimprovedfunction.ThesearchfortheIDof"selectall"is
- //OKas-is,becausewesawhowfasttheIDsearchis.
- //ThesearchfortheCLASSof"selectable"wasnotwell-designedthough,
- //becausewesawasearchbyCLASSisveryinefficient.
- //Firststepwasimprovingthesearchbysupplyingasmuchinformationasweknow.
- //WenarrowedthesearchtoonlycheckboxeswiththeCLASSofselectable.
- //Thisshouldimproveoursearch
- //Further,wecancachethissearchbecausewewillonlyneedtoperformitonce
- //Finally,wecanperformthissearchbeforetheselectallcheckboxiseven
- //checked(whenthepageisfinishedloading),sothatthesearchiscompleted
- //andcachedbeforetheuserevenusesit.
- //These3simpleperformancestepsgavemea200%increaseinspeedwhentested
- //onapagewith200rowsofdata.
- varselectable=$(":checkbox.selectable");
- functionselectAll()
- {
- varchecked=$("#selectall").attr("checked");
- selectable.each(function(){
- varsubChecked=$(this).attr("checked");
- if(subChecked!=checked)
- $(this).click();
- });
- }
#p#
关于性能的要点
使用JavaScript时,速度和性能绝对不是小问题。在现实中,创建jQuery的开发人员和处理浏览器内置JavaScript引擎的开发人员都非常关注性能问题。事实上,在最近6个月以来,浏览器开发的最重要问题就是JavaScript引擎的速度。浏览器开发者都致力于在下一年迅速提升JavaScript的执行性能,从而大大提高jQuery代码和JavaScript引擎的速度。来自这些“速度之战”的消息表明,提升JavaScript性能是大势所趋。
领导jQuery项目的JohnResig一直都在谈论他的***“Sizzle”选择引擎。他从头编写了一个选择引擎,并声称初步结果表明它比Firefox要快4倍。这是巨大的速度提升!在我撰写本文的***部分时,jQuery1.3已经发布,并且包含了Sizzle选择引擎。jQuery声称,在所有浏览器上运行的总体结果表明选择引擎的1.3版本比1.2.6版本的快49%。此外,1.3发布版在HTML注入(向DOM添加新的元素)上改进了6倍,在函数定位上改进了3倍。在我完成本文时,很多人都更新到了***的jQuery发布版,这是非常令人激动的!
影响JavaScript性能的另一个因素是浏览器,如前所述,它的影响是所选的库的9倍。Firefox和Chrome在“最快JavaScript引擎”之战中各有胜负,而Safari的参与让竞争更加激烈。从我们上面的测试中,可以看到Chrome在JavaScript引擎性能方面远远超过Firefox,但是Firefox3.1将包含新的TracemonkeyJavaScript引擎,届时其速度将比当前的JavaScript引擎3.0快20至40倍(这是他们声称的,不是我的观点),真不可思议!在未来一两年内,您将看到底层JavaScript引擎和JavaScript库的速度得到巨大改进,从而导致使用JavaScript的Web应用程序将变得更加复杂。
如果您正在决定是使用JavaScript库还是自己编写JavaScript,那么需要考虑的另一件事情是处理和调试JavaScript库所需的全部工作。最近几年以来,有数百位用户一直在维护库中的每一个函数。您可能要忙到深夜,甚至筋疲力尽地编写自己的函数。
您更相信谁呢?另外,即使您能编写出比jQuery库更快的代码,您是否想过使用jQuery库能够获得更多的优势?您是否为了辛苦地编写自己的代码而放弃使用非常便利的jQuery及其函数库?自己编写代码不仅需要大量时间,并且还会产生更多bug,因此我还是建议使用现成的jQuery库。
我***讨论的要点可能会让一些人沮丧,但是我们必须考虑编写这些jQuery库的程序员。他们当中的一些是最棒的,并且他们编写的超级优秀的代码(一般人不能编写这样出色的代码)都收入到这些库中。我承认自己远远不如编写jQuery库的程序员。因此,为何不利用他们的智慧?
结束语
本文从总体上讨论了jQuery和JavaScript库的性能。通过对选择方法进行大量的测试,您看到这些库之间的速度存在巨大的差距,并且jQuery是最快的库之一。不过,即使您选择了最快的JavaScript库,还是不能解决Web应用程序的性能问题,因为浏览器对性能的影响比库强9倍。如果您能够控制用户使用特定的Web浏览器,那么就让他们使用最快的浏览器。找到能够最快地运行您的Web应用程序的浏览器,并让用户通过使用它从中受益。理想情况下,让最慢的JavaScript浏览器消失意味着出现更快的Web应用程序。
***,我们快速查看了jQuery和浏览器的JavaScript引擎即将推出的改进。在我撰写本文的结尾部分时,jQuery1.3已经发布了,它承诺在选择和代码的其他方面实现跳跃式性能改进。此外,Firefox还承诺它的下一代JavaScript引擎会快20至40倍!这些迹象表明,在未来的一两年内,JavaScript环境会在性能上取得重大突破。在不久的将来,复杂的Web应用程序会日益流行,因为快速运行这些程序的条件已经成熟。
【编辑推荐】
- jQuery高级应用:优化Web应用程序的***绝招
- jQuery四大天王:核心函数详解
- jQuery中10个强大的遍历函数
- 即刻提升jQuery性能的十个技巧
- 一些应该熟记于心的jQuery函数和技巧