jQuery應用程序性能指標和調優
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函數和技巧