何謂大量元素選取器
這裡所談的JavaScript大量元素選取器是指getElementsByTagName()之類的元素選取器,此類元素選取器與getElementById()不同,getElementById()只回傳一個元素物件,而大量元素選取器會回傳一個陣列物件,陣列物件中包含所有合乎規則的元素內容。在撰寫HTML5程式碼時,心裡面突然有個念頭,這些大量元素選取器(含HTML5才提供的功能)在走訪一個又大又深DOM時,效能如何?
HTML 4主角有:getElementsByName(),getElementsByTagName()
HTML 4派出兩位主角分別是getElementsByName()與getElementsByTagName()。
- getElementsByName(屬性名稱):以元素屬性 name="value" 的value來取得所有符合名稱的元素集合。
- getElementsByTagName(元素名稱):以元素名稱,例如"p",來取得所有p元素集合。
HTML5主角有:getElementsByClassName(),querySelectorAll()
HTML5派出兩位主角分別是getElementsByClassName()與querySelectorAll()。
- getElementsByClassName(類別名稱):以元素屬性 class="value" 的value來取得所有符合名稱的元素集合。
- querySelectorAll("CSS Selector"):直接透過CSS選擇器規則來進行選取,符合CSS選擇器規則(支援CSS3的虛擬類別)的元素將被選取。
又深又長的DOM
以下JavaScript程式要建立一個又深又長的DOM,以增加走訪DOM的難度。
// 先在頁面上新增一個元素 var test = document.getElementById("test"); for (var i = 0; i < 1000; i++) { var d = document.createElement("div"); d.setAttribute("id", "div" + i); d.setAttribute("class", "div100") for (var j = 0; j <= 1000; j++) { var para = document.createElement("p"); para.setAttribute("class", "sale"); para.setAttribute("name", "sale"); var txt = document.createTextNode(j); para.appendChild(txt); d.appendChild(para); } // 讓層數加深 if (i === 0) { test.appendChild(d); } else { var dp = document.getElementById("div" + (i - 1)); dp.appendChild(d); } }
每一個div裡有1001個p元素,第1002個是div元素,再包1001個p元素,第1002個是div元素...會有1000層的深度及1001000個p元素。
// 測試取得大量元素的時間 var star_time = new Date(); var select_para = document.getElementsByName("sale"); //var select_para = document.getElementsByTagName("p"); //var select_para = document.getElementsByClassName("sale"); //var select_para = document.querySelectorAll("p"); //var select_para = document.querySelectorAll(".sale"); var end_time = new Date(); console.log("取得p元素個數: " + select_para.length); console.log("Start: " + star_time.getMinutes() + ":" + star_time.getSeconds() + ":" + star_time.getMilliseconds() + ", time: " + star_time.getTime()); console.log("End: " + end_time.getMinutes() + ":" + end_time.getSeconds() + ":" + end_time.getMilliseconds() + ", time: " + end_time.getTime());
這邊讓我偷懶一下,用偷懶的寫法。這樣就可以取得每個大量元素選取器的執行時間。
測試的主角有Chrome 21, Firefox 14
Internet Explorer 9不測的原因
- HTML5支援不足,不測試(也無法測)
- DOM 跑好久好久,不想測(直接按X)
另外,如果用p元素下去選取,選取的個數會多2,那是因為我使用ASP.NET MVC 4預設樣版的關係,裡面會多2個p元素。2個對結果的影響太小,就不修正。
Chrome 21
- document.getElementsByName("sale")
-
- 取得p元素個數: 1001000
- Start: 29:13:392, time: 1344223753392
- End: 31:54:795, time: 1344223914795
- document.getElementsByTagName("p")
-
- Start: 31:54:795, time: 1344223914795
- End: 31:54:795, time: 1344223914795
- document.getElementsByClassName("sale") (HTML5)
-
- 取得p元素個數: 1001000
- Start: 32:41:499, time: 1344223961499
- End: 32:41:499, time: 1344223961499
- document.querySelectorAll("p") (HTML5)
-
- 取得p元素個數: 1001002
- Start: 33:41:67, time: 1344224021067
- End: 33:41:120, time: 1344224021120
- document.querySelectorAll(".sale") (HTML5)
-
- 取得p元素個數: 1001000
- Start: 35:5:814, time: 1344224105814
- End: 35:5:883, time: 1344224105883
這裡出現53ms差距。
這裡出現69ms差距。
Firefox 14
- document.getElementsByName("sale")
-
- 取得p元素個數: 1001000
- Start: 43:17:376, time: 1344224597376
- End: 43:17:376, time: 1344224597376
- document.getElementsByTagName("p")
-
- 取得p元素個數: 1001002
- Start: 41:58:801, time: 1344224518801
- End: 41:58:801, time: 1344224518801
- document.getElementsByClassName("sale") (HTML5)
-
- 取得p元素個數: 1001000
- Start: 40:51:601, time: 1344224451601
- End: 40:51:601, time: 1344224451601
- document.querySelectorAll("p") (HTML5)
-
- 取得p元素個數: 1001002
- Start: 39:44:850, time: 1344224384850
- End: 39:44:923, time: 1344224384923
- document.querySelectorAll(".sale") (HTML5)
-
- 取得p元素個數: 1001000
- Start: 37:40:971, time: 1344224260971
- End: 37:41:49, time: 1344224261049
這裡出現73ms差距。
這裡出現78ms差距。
大量元素選取器PK結果
HTML 4與HTML5的大量元素選取器選取效能PK結果,HTML4以2:1獲勝。HTML 4的getElementsByName()與getElementsByTagName()都以非常快的速度執行的深層DOM與一百萬筆以上p元素的選取,快到以ms單位都分不出差異。
HTML5的getElementsByClassName()取得和HTML4平手效能,也是快到ms單位都分不出差異。不過在querySelectorAll()差異就出現在,在1000層的深度的走訪及1001000個p元素選取過程,使用平均50ms ~ 80ms的時間效能(依JavaScritp引擎不同而會有差異),所以我們可以得到結論是,相對於前面三個大量選取器,querySelectorAll()本身是一個執行效率較差的大量選擇器函式。
那我要不要用querySelectorAll()呢
這樣想,你的網頁會不會有1000層的深度?會不會有一百萬個p元素?如果不會,我相信querySelectorAll()的優點絕對大於缺點。我們在CSS所學習的Selector技巧,可以直接在JavaScript的選取器裡使用,這在某些場境下是非常好用的,更重要的是querySelectorAll()裡的Selector是支援CSS3 Selector的,這又讓我們在處理特別情境下更是方便。
querySelectorAll()執行效率雖然是有ms的差異,但當你享受到querySelectorAll()帶來的好處後,你就會忽略那ms的差異。(就處理速度來看,querySelectorAll()還是很快,只是他的對手太強了)
沒有留言:
張貼留言
感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。