天天看點

jQuery各種show/hide方式的性能測試

這篇文章是jQuery各種show/hide方式的性能測試。作者之是以測試這個源于Robert Duffy在San Francisco舉行的jQuery大會上的一句話:“.hide()和.show()的執行速度會比直接改變css慢”。但由于未能找Robert Duffy問明原因,是以作者就自己去做了這個測試。下面的翻譯并不是全文翻譯,隻節選了一些重點。

用作測試的是一個含有100個div的HTML頁面,div帶有class和一些内容。為了排除掉尋找這些div所花費的時間,是以把選擇器$('div')緩存起來了。用作測試的jQuery版本是1.4.2,是以測試結果也隻是針對這個版本,在其他版本可能就不是這些結果了。

測試的jQuery方法分别是:

  • .toggle()
  • .show() 和 .hide()
  • .css({'display':'none'}) 和 .css({'display':'block'})
  • .addClass('hide') 和 .removeClass('hide')
  • 改變<style>元素的一個屬性

.show() 和 .hide()

在所有浏覽器中,這兩個方法在隐藏DOM元素上相對來說比較慢。主要原因在于.hide()方法必須先儲存元素的"display"屬性,這樣.show()才能把元素恢複到原來的狀态。這裡用到了.data()這個jQuery方法,把資訊儲存在DOM元素上。為了達到這個目的,.hide()在每個元素上循環了兩次,一次用來儲存目前的"display"值,一次用來更新樣式"display" 為"none"。根據源代碼上的注釋,這樣做是為了防止浏覽器在每個循環上進行重新渲染(reflow)。.hide()方法還會檢查你是否傳遞了使用動畫效果的參數,就算傳入一個"0"也會讓性能大打折扣。在第一次調用.hide()的時候性能最慢,在之後再調用則會變快。

Browser hide/show
FireFox 3.6 29ms / 10ms
Safari 4.05 6ms / 1ms
Opera 10.10 9ms / 1ms
Chrome 5.0.3 5ms / 1ms
IE 6.0 31ms / 16ms
IE 7.0 15ms / 16ms

.toggle()

這個方法是最慢的。它會檢查選擇器傳回的每一個元素目前是否可見,如果可見的話就調用.hide()方法,不可見則調用.show()方法。不但如此,它不僅會檢查你是否傳遞了一個boolean值進去阻止.hide()或者.show()的執行,還會檢檢視你是否傳入了function來進行切換(toggle)而不是對可見性進行切換。看起來這個方法還有很大的改善空間,例如可以先一次過把隐藏的元素 select出來,然後調用.show()方法,同時把其餘的元素select出來調用.hide()方法。

Browser hide/show
FireFox 3.6 80ms / 59ms
Safari 4.05 24ms / 30ms
Opera 10.10 67ms / 201ms
Chrome 5.0.3 55ms / 20ms
IE 6.0 296ms / 78ms
IE 7.0 328ms / 47ms

.addClass() 和 .removeClass()

這是兩個很漂亮的隐藏/顯示DOM元素方法。在Firefox上它的速度是.show()和.hide()的兩倍,而在Safari上則是三倍。不過在IE6,IE7,Chrome和Opera上,兩種方法幾乎沒什麼差别。值得一提的是,對于100個DOM節點來說,兩種方法在Firefox上相差18ms,在Safari相差4ms,速度的差異隻會展現在大量節點選擇的時候。不過增加和移除class需要你花費更多的工作,因為你需要建立一個用于隐藏的class,然後還要時刻關注着這個class的優先級以保證DOM能隐藏。jQuery增加和移除class是通過字元串操作的,是以我覺得随着元素上class數量的增加,這個方法會變慢,但是我還沒對此進行測試過。

Browser hide/show
FireFox 3.6 11ms / 11ms
Safari 4.05 2ms / 2ms
Opera 10.10 6ms / 3ms
Chrome 5.0.3 3ms / 1ms
IE 6.0 47ms / 32ms
IE 7.0 15ms / 16ms

.css({'display':'none'}) 和 .css({'display':'block'})

這兩個方法也很漂亮。相對于.addClass()和.removeClass(),IE6/7和Opera上的速度都得到了提升,而在其他浏覽器上則能保持水準。當你知道要改變的元素的目前display樣式,或者沒有通過inline的方式去改變元素的display樣式時,這兩個方法很好用。如果你通過 inline的方式改變了display樣式,那麼你需要確定在使得元素重新可見時display值要設定正确。如果你隻是使用了元素的預設 display值或者在css裡設定display值,那麼你隻需要用類似.css({'display':''})的方法移除樣式,元素就會恢複到它在 css上的樣式或者預設display值。作為一個類庫,jQuery不能假定元素的display不是通過inline方式設定的,是以它需要被人手的去确定。不過既然你知道你不會去inline的設定display,那麼你就可以去避免這個造成緩慢的主要因素。

Browser hide/show
FireFox 3.6 14ms / 12ms
Safari 4.05 2ms / 1ms
Opera 10.10 2ms / 2ms
Chrome 5.0.3 2ms / 1ms
IE 6.0 16ms / 16ms
IE 7.0 0ms / 0ms // 少于15ms會變成0ms,具體看這裡

禁止樣式表

純粹為了好玩,我想:如果我們不在每個dom節點上花功夫,而是去搗鼓樣式表會怎樣呢?這樣會提高速度嗎?其實就日常使用來說,上面的測試用到的方法已經足夠快了,但是如果頁面上有10000個節點需要進行隐藏和顯示呢?隻是把它們全部選擇出來就已經夠慢了。如果我可以控制樣式表,那麼就可以完全避免這些時間花費了。不過我得告訴你,這個方法是有很大風險的。

風險在于控制樣式表時的跨浏覽器問題。首先,我嘗試能不能通過jQuery插入一個帶有class的"style"标簽,但是卻出現了跨浏覽器問題。然後我嘗試用javascript去建立stylesheet節點和class,但是實在有太多的API了,要搞清楚需要花不少的時間。最後,放棄了程式設計的方式,我在head區裡寫了一個帶有class的style标簽。通過程式設計的方式來建立stylesheet實在是太慢了,但是如果它一旦被建立好,那麼給它一個ID和使用它的"disabled"屬性就是輕而易舉的事情了。

然後在javascript裡:

搞定!所有帶有"special_hide"這個class的元素都顯示出來了。要隐藏它們,你隻需要……

現在它們全部都隐藏了。總的javascript耗時在所有浏覽器上都是0-1ms。你的javascript 隻是用來改變一個屬性。當然,浏覽器還是需要花費時間去重新渲染頁面的,但是實際上你已經避免了javascript的處理時間。如果你調用了.toggle(),.hide()或者 .css()這幾個方法,那麼這個方法就會失效。因為那幾個方法會通過内聯方式設定css樣式,這些樣式有更高的優先級。要重新使這個方法生效,隻需調用.css('display', '') 把内聯的樣式移除掉。這個方法同樣需要花費你更多的精力,因為那需要去定義class,同時把這些class賦給頁面上需要進行顯示/隐藏的元素,但是如果你所要處理的元素數量是極其龐大的話,那麼這也許是值得的。

簡要回顧一下,下面是改變元素顯示狀态的方法,按照最快到最慢的次序排列:

  • 禁用/啟用樣式表
  • .css('display', ''), .css('display', 'none')
  • .addClass(), .removeClass()
  • .show(), .hide()
  • .toggle()

需要注意的是,在大多數的情況下,這些方法都足夠的快了。當你要操作很大的jQuery集合時,那麼.show() 和 .hide()方法在IE下就會變得很慢了,這是你可能要用addClass() 或者 .removeClass()方法。禁用/啟用樣式表的方法隻有在很極端的情況下才有必要用到。

Translated by icyfire @ company ON Jul 26, 2010