JavaScript大量元素選取器效能大PK(含HTML5)

何謂大量元素選取器

這裡所談的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不測的原因

  1. HTML5支援不足,不測試(也無法測)
  2. 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

這裡出現53ms差距。

document.querySelectorAll(".sale") (HTML5)
  • 取得p元素個數: 1001000
  • Start: 35:5:814, time: 1344224105814
  • End: 35:5:883, time: 1344224105883

這裡出現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

這裡出現73ms差距。

document.querySelectorAll(".sale") (HTML5)
  • 取得p元素個數: 1001000
  • Start: 37:40:971, time: 1344224260971
  • End: 37:41:49, time: 1344224261049

這裡出現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()還是很快,只是他的對手太強了)

沒有留言:

張貼留言

感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。