5

Provided you have a container div with hundreds of very simple children elements such as the following:

<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>

Would including an unique id for each single element harm (client) performance in any (meaningful) way, be it rendering, javascript or memory wise?

Why I'm asking: I may need from time to time to reference specific items, and I'm trying to figure out whether I should precalculate in advance which items I will need to select, giving ids to them and leaving the rest out, or just assigning ids to all of them, which would make the process more straight forward but I wonder if this may be an overkill somehow.

Bonus points (if I could actually give them) if someone can talk about how this is handled by modern browsers and why it would/would not make a difference in terms of how browsers render and manage the DOM.

Mahn
  • 16,261
  • 16
  • 62
  • 78
  • 2
    you can actualy give bonus points, yopu seem toi have plenty. just set a bounty ;-) – Pevara Aug 07 '12 at 22:56
  • 1
    I made [a simple JSPerf test](http://jsperf.com/html-dom-id-vs-no-id) and I get very mixed results (the test might not be good though), even in the same browser (Chrome) in different windows. Parsing the HTML might take most of the time, so [here is a version](http://jsperf.com/html-dom-id-vs-no-id/2) were each element has the same number of attributes, but same mixed results. I think performance wise (like building an index etc) this really does not make a difference. – Felix Kling Aug 07 '12 at 23:19
  • @FelixKling interesting, thanks for putting together the tests; on my end (Chrome 20 & Firefox 14) it looks like the no id version is slightly (very slightly) faster. – Mahn Aug 08 '12 at 00:48

5 Answers5

3

At the very most, I'm guessing that the basic few things a browser would do is assign the ID as a property to each element when building the DOM structure, as well as store the IDs in a hash table to facilitate things like #id selectors, document.getElementById() and idref lookups later. I don't think this is going to cause even a slight dent in observed performance or memory usage, as hash tables and the DOM are designed to be very well-optimized.

That said, if IDs aren't needed on your elements at all, then there quite simply is no point in assigning them IDs; you're going to end up with a whole lot of markup bloat instead. As Dan Davies Brackett mentions, that will obviously cause a slowdown since it depends on the client connection.

If you can afford to reference these elements using CSS selectors, you can always use :nth-child() to look up specific children. If you need to support older browsers, there's always a CSS2 solution. See these questions:

Community
  • 1
  • 1
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
  • 2
    I like the term "observed performance", I am totally stealing that. Out of votes though :( – Esailija Aug 07 '12 at 22:59
  • Great answer, thanks. I was hoping I could get some Chrome or Mozilla dev to step up and post a lenghty technical answer on how this would not affect performance on a modern browser but I guess that's not gonna happen :-) – Mahn Aug 08 '12 at 00:58
  • @Mahn: Well, there's at least one of each who drops by once in a while. Maybe if you're lucky... – BoltClock Aug 08 '12 at 01:00
  • Looping and assigning IDs for hundreds of items could get very ugly on the reflow front depending on how the page is arranged/how much html content each item has and other factors. – Erik Reppen Sep 17 '12 at 20:17
  • @Erik Reppen: Sounds nasty. I've removed that bit from my answer now. – BoltClock Sep 17 '12 at 20:19
  • Or just bake IDs in on the servers side or attach to the DOM with IDs in one block if you're building client-side. That way it's one reflow calc rather than potentially hundreds to the element and all siblings and maybe sibling containers of stuffContainer every time an ID gets set. With all the various ways to access elements with CSS now, pretty much any tweak to an HTML element sets off reflow. – Erik Reppen Sep 17 '12 at 20:27
2

As BoltClock implies, the answer to most performance questions is 'measure it!'. That said, you missed one potential axis for measurement: download size. Adding ID attributes to more elements than is necessary will add to your byte weight, not least because the elements are required to be unique (which means they won't zip as well as non-unique attributes might).

Dan Davies Brackett
  • 9,811
  • 2
  • 32
  • 54
2

The original Q isn't very specific about contents/purpose and there should be variation, depending, IMO. I definitely disagree with the current accepted answer on one point. Looping through and attaching new IDs to a ton of HTML that's already rendered could cause massive amounts of reflow calculation which could get ugly depending on what 'stuffContainer' represents.

Build With IDs First From Server or Inject as Single Block on Client-Side if You Must

As a general rule, avoid hitting the DOM with changes repeatedly if you can avoid it. IDs built beforehand on the server is pretty negligible as far as the browser loading the page, IMO. Sure, it's a larger, and consequently slower hash-table but if we're talking hundreds and not tens of thousands I seriously doubt you're going to notice.

A more efficient client-side approach in the case of something like a select list built from data would be to build as a string first, with IDs and all, and then assign to innerHTML of a container or if like some of my js chat colleagues, you have a bizarre hang-up about innerHTML in every possible use-case even though it's in the spec now, at the very least build and append to a document fragment first. and then append that to your container.

Data-Attributes or Classes Over IDs

IMO, the smell-factor isn't so much about performance but rather HTML bloat and creating an ID dependency where none is needed, thereby blocking something else that might find a custom ID on one of your single-item divs useful. IDs are definitely the ideal way to narrow down an element look-up in JavaScript but in cases of containers with contents you'll get more flexibility out of ID'd containers than ID'ing every child item. The performance gain of one-stepping vs. two-stepping isn't worth the flexibility cost of applying generic IDs to elements.

As an alternative you can use classes with unique values or the data attribute, e.g. 'data-itemId="0"'. For smaller sets of HTML like a custom select list where IDs are connected to some server-side indexing system for ease of updating data I would tend to favor this highly visible approach as it makes it easier to understand the architecture, but it adds a lot of needless attributes to track in scenarios where hundreds to thousands of items might be involved.

Or Ideally (in most cases), Event Delegation

Most ideally, IMO, you avoid additional attributes altogether in cases where you only care about the child single-item element you're clicking and not what it's 'ID' is or the order those single-item containers will remain static and you can safely assume the positions are the effective IDs. Or another scenario where this might work with a non-static single-item set is if you've got single-item data in an array of objects that gets shuffled and then used to build and replace HTML on user-initiated sorts that will always tie order of the HTML to other data-tracking dependencies.

The non-Jquery approach (untested):

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);

    } );

Or simple JQuery delegation style (also, untested):

$('#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);
} );
Erik Reppen
  • 4,605
  • 1
  • 22
  • 26
  • I agree with pretty much everything you've written and you have my upvote, but I have to be honest, I was specifically looking for the answer on how the browser would react provided the IDs were generated server side when I posted the question, which @BoltClock covers more directly. But I would accept your answer aswell I could accept twice. – Mahn Sep 18 '12 at 00:22
  • No prob. Upvotes appreciated. I've learned to embrace being the TLDR-maid and not the bride. – Erik Reppen Sep 18 '12 at 16:05
1

There are no significant performance degradations from using id attributes, even when used hundreds of times. Although it would be slightly faster to hand-pick the elements you need to uniquely identify, in my opinion the performance improvement would not justify the extra time required to do so.

That being said, I'm not sure id attributes are even required in this case. If you were to use jQuery, you could select the fourth element, for example, using the following code:

$('.single-item').eq(3);
jeff
  • 8,300
  • 2
  • 31
  • 43
  • Probably selecting them by id would still be faster than using jQuery's eq, wouldn't it? – Mahn Aug 08 '12 at 00:51
  • @Mahn - Yes, but again, I don't think the performance improvement justifies spending the time needed to add each `id` attribute. Also, removing the `id` attributes would decrease the file size. – jeff Aug 08 '12 at 02:35
0

Using id's on everything would be a bit overkill in this case. I understand where you are coming from, but if you use a language like jQuery, selecting the children would be easy considering the structure. Here is an example of how you might know which one of the div's was clicked:

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

This is just a small example, but as you can see, you are able to access each div for whatever you need to do. This will keep the html file less cluttered from excessive id tags, along with keeping your file size a little bit smaller (not to mention save you the headache from generating every unique id).

dash
  • 21
  • 4
  • 1
    That jQuery code is very problematic performance-wise. If you have hundreds of elements with that class, you should be using [event delegation](http://api.jquery.com/on/#direct-and-delegated-events). – bfavaretto Aug 07 '12 at 23:06
  • Somewhat contradictory to scrimp on id attributes to save bandwidth, then include a 4,000 line library as an alternative. – RobG Aug 08 '12 at 00:34