jquery的show/hide性能測試
這篇文章是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()方法。禁用/啟用樣式表的方法只有在很極端的情況下才有必要用到