这个部分介绍一些性能调优知识,以及改进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();
- });
- }