jquery的show/hide性能測試

jopen 12年前發布 | 34K 次閱讀 jQuery Ajax框架

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


用作測試的是一個含有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>元素的一個屬性




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




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




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




這兩個方法也很漂亮。相對于.addClass() 和.removeClass(),IE6/7和Opera上的速度都得到了提升,而在其他瀏覽器上則能保持水準。當你知道要改變的元素的當前 display樣式,或者沒有通過inline的方式去改變元素的display樣式時,這兩個方法很好用。如果你通過inline的方式改變了 display樣式,那么你需要確保在使得元素重新可見時display值要設置正確。如果你只是使用了元素的默認display值或者在css里設置 display值,那么你只需要用類似.css({'display':''})的方法移除樣式,元素就會恢復到它在css上的樣式或者默認display值。作為一個類庫,jQuery不能假定元素的display不是通過inline方式設置的,所以它需要被人手的去確定。不過既然你知道你不會去inline的設置display,那么你就可以去避免這個造成緩慢的主要因素。
這兩個方法也很漂亮。相對于.addClass()和.removeClass(),IE6/7和Opera上的速度都得到了提升,而在其他瀏覽器上則能保持水準。當你知道要改變的元素的當前display樣式,或者沒有通過inline的方式去改變元素的display樣式時,這兩個方法很好用。如果你通過inline的方式改變了display樣式,那么你需要確保在使得元素重新可見時display值要設置正確。如果你只是使用了元素的默認 display值或者在css里設置display值,那么你只需要用類似.css({'display':''})的方法移除樣式,元素就會恢復到它在 css上的樣式或者默認display值。作為一個類庫,jQuery不能假定元素的display不是通過inline方式設置的,所以它需要被人手的去確定。不過既然你知道你不會去inline的設置display,那么你就可以去避免這個造成緩慢的主要因素。
這兩個方法也很漂亮。相對于.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"屬性就是輕而易舉的事情了。
純粹為了好玩,我想:如果我們不在每個dom節點上花功夫,而是去搗鼓樣式表會怎樣呢?這樣會提高速度嗎?其實就日常使用來說,上面的測試用到的方法已經足夠快了,但是如果頁面上有10000個節點需要進行隱藏和顯示呢?只是把它們全部選擇出來就已經夠慢了。如果我可以控制樣式表,那么就可以完全避免這些時間花費了。不過我得告訴你,這個方法是有很大風險的。
風險在于控制樣式表時的跨瀏覽器問題。首先,我嘗試能不能通過jQuery插入一個帶有class的"style"標簽,但是卻出現了跨瀏覽器問題。然后我嘗試用javascript去創建stylesheet節點和class,但是實在有太多的API了,要搞清楚需要花不少的時間。最后,放棄了編程的方式,我在head區里寫了一個帶有class的style標簽。通過編程的方式來創建stylesheet實在是太慢了,但是如果它一旦被創建好,那么給它一個ID和使用它的"disabled"屬性就是輕而易舉的事情了。
純粹為了好玩,我想:如果我們不在每個dom節點上花功夫,而是去搗鼓樣式表會怎樣呢?這樣會提高速度嗎?其實就日常使用來說,上面的測試用到的方法已經足夠快了,但是如果頁面上有10000個節點需要進行隱藏和顯示呢?只是把它們全部選擇出來就已經夠慢了。如果我可以控制樣式表,那么就可以完全避免這些時間花費了。不過我得告訴你,這個方法是有很大風險的。
風險在于控制樣式表時的跨瀏覽器問題。首先,我嘗試能不能通過jQuery插入一個帶有class的"style"標簽,但是卻出現了跨瀏覽器問題。然后我嘗試用javascript去創建stylesheet節點和class,但是實在有太多的API了,要搞清楚需要花不少的時間。最后,放棄了編程的方式,我在head區里寫了一個帶有class的style標簽。通過編程的方式來創建stylesheet實在是太慢了,但是如果它一旦被創建好,那么給它一個ID和使用它的"disabled"屬性就是輕而易舉的事情了。
1  2  3   <style id="special_hide">.special_hide { display: none; }</style>  <!--  ...  -->  <div class="special_hide">Special hide DIV</div>


1   $('#special_hide').attr('disabled, 'true');


1   $('#special_hide').attr('disabled', 'false');

簡要回顧一下,下面是改變元素顯示狀態的方法,按照最快到最慢的次序排列:
  • 禁用/啟用樣式表
  • .css('display', ''), .css('display', 'none')
  • .addClass(), .removeClass()
  • .show(), .hide()
  • .toggle()

.show() 和 .hide()

.toggle()

.addClass() 和 .removeClass()

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

禁止樣式表

然后在javascript里:

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

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

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

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!