2012-08-07 42 views
5

只要你有數百個非常簡單的子元素的div容器,如以下幾點:HTML DOMs,ids vs no ids?

<div id="stuffContainer" class="item-container"> 
    <div class="single-item"></div> 
    <div class="single-item"></div> 
    <div class="single-item"></div> 
    <div class="single-item"></div> 
    <div class="single-item"></div> 
    <div class="single-item"></div> 
    [...] 
</div> 

請問,包括對任何(有意義)的方式各單個元素傷害(客戶端)性能的唯一的ID,無論是渲染,JavaScript或內存明智?

爲什麼我問:我可能需要不時地參考具體項目,我想知道我是否應該事先預先計算哪些項目需要選擇,給他們ID並離開剩下的,或者只是給所有人分配ID,這會使得這個過程更加直接,但我想知道這可能是一個矯枉過正的問題。

如果有人可以談論現代瀏覽器是如何處理這個問題的,並且爲什麼它在瀏覽器呈現和管理DOM方面不會產生什麼影響,那麼獎金點(如果我真的可以給他們的話)。

+2

可以actualy給予加分,yopu似乎TOI有很多。只是設置一個賞金;-) – Pevara 2012-08-07 22:56:46

+1

我做了[一個簡單的JSPerf測試](http://jsperf.com/html-dom-id-vs-no-id)和我得到非常混合的結果(測試可能不好儘管),即使在不同的窗口中使用同一瀏覽器(Chrome)。解析HTML可能需要大部分時間,所以[這裏是一個版本](http://jsperf.com/html-dom-id-vs-no-id/2)是每個元素具有相同數量的屬性,但結果相同。我認爲性能明智(如建立索引等)這實在沒有什麼差別。 – 2012-08-07 23:19:54

+0

@FelixKling有趣,感謝您將測試放在一起;在我的最後(Chrome 20和Firefox 14),它看起來像no id版本略微(稍微)更快。 – Mahn 2012-08-08 00:48:46

回答

3

在最多的時候,我猜測瀏覽器做的幾件基本事情是在構建DOM結構時將ID作爲屬性分配給每個元素,並將ID存儲在散列表中以便於諸如#id選擇器,document.getElementById()和稍後的idref查找。我不認爲這會導致觀察到的性能或內存使用量出現輕微的下降,因爲散列表和DOM被設計爲非常優化。

也就是說,如果您的元素在所有上都不需要ID,那麼在分配ID時就沒有意義了。您最終會遇到很多標記膨脹問題。正如丹·戴維斯·布拉克特所言,顯然會導致放緩,因爲它取決於客戶端連接。

如果您可以使用CSS選擇器引用這些元素,則始終可以使用:nth-child()來查找特定的子元素。如果您需要支持舊版瀏覽器,那麼總會有一個CSS2解決方案。看到這些問題:

+2

我喜歡「觀察到的表現」這個詞,我完全在偷。雖然:( – Esailija 2012-08-07 22:59:18

+0

很好的答案,謝謝。我希望我可以讓一些Chrome或Mozilla的開發者加強併發布一篇關於如何不會影響現代瀏覽器性能的長篇技術性答案,但我想這不會發生:-) – Mahn 2012-08-08 00:58:43

+0

@Mahn:呃,每個人中至少有一個在一段時間內掉落一次。也許如果你幸運的話...... – BoltClock 2012-08-08 01:00:14

1

曾經有數以百計的時候是使用id屬性沒有顯著的性能下降,甚至。儘管手動選擇需要唯一標識的元素會稍微快一點,但我認爲,性能提升並不能證明這樣做需要額外的時間。

這就是說,我不確定id屬性甚至需要在這種情況下。如果你使用jQuery,您可以選擇第四個元素,例如,使用下面的代碼:

$('.single-item').eq(3); 
+0

可能通過id選擇它們仍然會比使用jQuery的eq更快,不是嗎? – Mahn 2012-08-08 00:51:17

+0

@Mahn - 是的,但我不認爲性能改進證明需要花時間來添加每個「id」屬性。另外,刪除'id'屬性會減小文件大小。 – jeff 2012-08-08 02:35:08

2

由於BoltClock意味着,回答最多的性能問題是「測量它!」。這就是說,你錯過了一個潛在的測量軸:下載大小。將ID屬性添加到超過必需的元素將增加字節權重,這不僅僅是因爲元素必須是唯一的(這意味着它們不會壓縮以及非唯一屬性)。

+0

偉大的觀點,謝謝! – Mahn 2012-08-08 00:51:39

0

在這種情況下,在所有內容上使用id都會有點矯枉過正。我明白你來自哪裏,但是如果你使用jQuery這樣的語言,考慮到結構,選擇孩子會很容易。這裏是點擊了哪個div的之一,你怎麼可能知道的例子:

$('.single-item').click(function() 
{ 
    var yourClickedDiv = $(this); 
    // execute the rest of your code here 
}); 

這只是一個小例子,但正如你所看到的,您可以訪問每個任何你需要做的的div 。這將使html文件不會因爲過多的id標籤而變得混亂,同時保持文件的大小更小一些(更不用說爲了生成每一個唯一的ID而讓你頭疼了)。

+1

這個jQuery代碼在性能方面是非常有問題的。如果您擁有數百個該類的元素,則應該使用[事件委託](http://api.jquery.com/on/#direct-and-delegated-events)。 – bfavaretto 2012-08-07 23:06:27

+0

與id屬性的scrimp有點矛盾,以節省帶寬,然後包含一個4000線庫作爲替代。 – RobG 2012-08-08 00:34:08

2

原始Q對於內容/目的不是很具體,應該有變化,取決於IMO。我絕對不同意目前接受的答案。循環遍歷並將新ID附加到已經呈現的大量HTML中可能會導致大量的迴流計算,這可能會因'stuffContainer'表示的內容而變得很難看。

建立與標識首先從服務器或注入作爲一個塊上的客戶端如果必須

作爲一般規則,避免擊中的變化DOM反覆,如果你能避免它。就像瀏覽器加載頁面IMO一樣,事先在服務器上構建的ID幾乎可以忽略不計。當然,這是一個更大,因此速度更慢的哈希表,但如果我們談論的是數百個而不是數萬個,我真的懷疑你會注意到。

對於類似於根據數據構建的選擇列表的情況,更有效的客戶端方法是首先將其構建爲字符串,包含ID和全部,然後分配給容器的innerHTML,或者如果像某些我的js聊天的同事們,在每一個可能的用例中,你都會對innerHTML有一個奇怪的掛斷,儘管它現在已經在規範中了,至少在構建並附加到文檔片段之後。然後將其附加到您的容器中。

數據的屬性或類在標識

IMO,氣味因子是不是這麼多的性能,而是HTML膨脹並創建一個ID依賴於需要無,從而阻斷別的東西可能在您的單個項目div上找到自定義ID很有用。 ID絕對是縮小JavaScript元素查找範圍的理想方式,但在容器內容的情況下,您將比ID'd每個子項目獲得更多的靈活性。一步與二步的性能增益不值得將通用ID應用於元素的靈活性成本。

作爲替代,您可以使用具有唯一值或數據屬性的類,例如, '數據的itemId = 「0」'。對於像定製選擇列表那樣的較小的一組HTML,其ID與某些服務器端索引系統連接以便於更新數據,但我傾向於贊成這種高度可見的方法,因爲它可以更容易地理解架構,但它增加了很多在涉及數百到數千項目的場景中跟蹤不必要的屬性。

或理想(在大多數情況下),事件代表團

最理想,國際海事組織,你完全避免附加屬性在情況下,你只在乎你一下孩子單項元素,而不是什麼它的'ID'是訂單這些單項貨物將保持靜態,並且您可以安全地假定這些頭寸是有效的ID。或者,這可能適用於非靜態單項集合的另一種情況是,如果您有一些對象數組中的單項數據被混洗,然後用於在用戶啓動的排序上構建和替換HTML,這些排序將始終將HTML的順序與其他數據跟蹤依賴關係聯繫起來。

非jQuery的方法(未經測試):

var myContainer = document.getElementById('stuffContainer'); 
//ignore following indent goof 

    myContainer.addEventListener('click', function(e){ 
     var 
      singleItem, 
      elementOriginallyClicked = singleItem = e.target, 
      stuffContainer = this; 

     //anything clicked inside myContainer will trigger a click event on myContainer 
     //the original element clicked is e.target 
     //google 'event bubbling javascript' or 'event delegation javascript' for more info 

     //climb parentNodes until we get to a single-item node 
     //unless it's already single-item that was originally clicked 
     while(!singleItem.className.match(/[=\s'"]single-item[\s'"]/g)){ 
      singleItem = singleItem.parentNode; 
     } 

     //You now have a reference to the element you care about 

     //If you want the index: 

     //Get the singleItem's parent's childNodes collection and convert to array 
     //then use indexOf (MDN has normalizer for IE<=8) to get the index of the single-item 

     var childArray = Array.prototype.slice.apply(stuffContainer.childNodes,[0]), 
     thisIndex = childArray.indexOf(singleItem); 

     doSomethingWithIndex(thisIndex); 
     //or 
     //doSomethingWithDOMObject(singleItem); 

    }); 

或者簡單的jQuery代表團風格(也未經測試):

$('#someContainer').on('click','.single-item', function(){ 
    var $_singleItem = $(this), //jq handles the bubble to the interesting node for you 
    thisIndex = $_singleItem.index(); //also getting index relative to parent 

    doSomethingWithIndex(thisIndex); 
    //or 
    //doSomethingWithJQObject($_thisItem); 
}); 
+0

我同意幾乎所有你寫的東西,你有我的贊成,但我必須誠實地說,我特意尋找答案,如果瀏覽器會在我發佈問題時提供ID生成服務器端的反應, @BoltClock覆蓋更直接。但我會接受你的答案,我也可以接受兩次。 – Mahn 2012-09-18 00:22:59

+0

沒有問題。 Upvotes讚賞。我已經學會了成爲TLDR女僕而不是新娘。 – 2012-09-18 16:05:38