views:

438

answers:

9

Hi

I repetitively use document.getElementById a lot on common CSS elements.

Would there be a significant performance gain if I created a global array to store all of my document.getElementById element in instead of refetching the element each time?

Example, instead of:

document.getElementById("desc").setAttribute("href", "#");
document.getElementById("desc").onclick = function() {...};
document.getElementById("desc").style.textDecoration = "none"
document.getElementById("asc").setAttribute("href", "#");
document.getElementById("asc").onclick = function() {...};
document.getElementById("asc").style.textDecoration = "none"
...

To simply do:

var GlobalElementId = [];
GlobalElementId ["desc"] = document.getElementById("desc");
GlobalElementId ["asc"] = document.getElementById("asc");
GlobalElementId [...] = document.getElementById(...);

GlobalElementId ["desc"].setAttribute("href", "#");
GlobalElementId ["desc"].onclick = function() {...};
GlobalElementId ["desc"].style.textDecoration = "none"
...
+2  A: 

Yes!

There was a situation not long ago where I was getting poor performance modifying elements. The solution was to build a dictionary like your example. I literally improved performance 1000 times (In IE6 at least).

var elementCache = {};
function buildElementCache() {
    elementCache[id] = {
        element1: document.getElementById(id + "1"),
        element2: document.getElementById(id + "2")
    } 
    // Etc...   
}
ChaosPandion
+1  A: 

For me, this would be more appropriate and good for performance :

var desc = document.getElementById("desc");
var asc = document.getElementById("asc");
desc.setAttribute("href","#");
asc.onclick = function() { ... }
...

After reconsidering what ChaosPandion said, I think one way you could do it :

var elements = ["desc", "asc", ...];
for(var i = 0; i < elements.length; i++) {
  GlobalElementId[elements[i]] = document.getElementById(elements[i]);
}
Soufiane Hassou
I want to make this a globalarray so that all functions can use it. Creating individual variables for each CSS element seems overkill to me. So instead, I thought I would just throw it all into a common array bucket. Would this not be appropriate for my use case?
TeddyH
Creating individual variables is definitely not the way to go.
ChaosPandion
well, if you have a lot of variables and if you'll need to do the same thing for many of them (a loop-able "thing") then maybe yes, it's better to use an array.But if there's no possible loop, you'll just make your code bigger with the same performance IMO.
Soufiane Hassou
Individual variables seems like a terrible idea, hence why I planned to use a hash-array.
TeddyH
I added some code, what do you think?
Soufiane Hassou
Thanks an interesting idea of doing it.
TeddyH
It is recommended you use this syntax for arrays ["desc", "asc", ...]
ChaosPandion
Thanks, I didn't know that ;)Any reason why it is recommended ?
Soufiane Hassou
Why use i as your indexer variable name?
ChaosPandion
well i is a common variable name as an indexer, I think it's ok to use it, I could've used 'index' but I don't see the point.
Soufiane Hassou
LOL sorry, I should never answer a question with a question. What I was trying to say is that it is short and just as understandable.
ChaosPandion
haha, I undestand now, thanks :p
Soufiane Hassou
A: 

Yes, but using an array is overdoing it.

See Soufiane Hassou´s answer for how to do it.

anddoutoi
I want to make this a globalarray so that all functions can use it. Creating individual variables for each CSS element seems overkill to me. So instead, I thought I would just throw it all into a common array bucket. Would this not be appropriate for my use case?
TeddyH
+1  A: 

Since you say "CSS elements" I suspect that a lot of your slow performance is not because of repetitive use of document.getElementById() (which you should avoid anyway) but rather how many times you modify the style object for a given node.

Every single time you change a property on style you force the browser to re-draw that element and possibly many others on the page.

var elem = document.getElementById( 'desc' );
elem.style.textDecoration = "none"; // browser re-draw
elem.style.borderWidth    = "2px";  // browser re-draw
elem.style.paddingBottom  = "5px";  // browser re-draw

Here, the better solution is to use CSS classes and switch or add/remove the class name from the node. This lets you pack in as many style changes you want at the cost of only a single re-draw.

var elem = document.getElementById( 'desc' );
elem.className = "whatever"; // Only one browser re-draw!
Peter Bailey
If you notice in my example, there is only 1 redraw. I'm dynamically creating HREF links and only set the style once.
TeddyH
this is still a good point. For whatever reason I had always used classes but I had not thought about this performance penalty before. Good to know.
corymathews
I was under the impression that most browsers cannot redraw until all scripts stop executing. Not that I am against using classes.
ChaosPandion
Browser redraws definitely *can* be a performance problem. Even if you only set the style once per element, that's one browser redraw per element. I've actually optimized this before by removing a table from the dom, modifying a bunch of its cells, and then re-adding it to the dom so there would only be 1 redraw.
Mike Blandford
In IE, the redraw is immediate. I'm not sure about other browsers
Mike Blandford
@TeddyH - Yes I see what you put in your example. But it's just that - an *example*. I never assume that the code someone posts in a question is the entirety of their work that causes them to come here and ask for help.
Peter Bailey
A: 

Depends on the definition of ‘significant’. A GlobalElementId.asc array access is much faster proportionally than a getElementById() call. But getElementById is still very fast compared to most other DOM manipulations your script is likely to be doing, and in all likelihood is only a very very tiny proportion of your script's execution time.

I'd write for readability first, for which Soufiane's answer would seem best. Only if in practice that part of the script was proving to be too slow would I bother starting to think about lookup caches, which add extra complexity (particularly if you start changing those elements at run-time).

Side-note: don't use setAttribute, it's bugged in IE and less readable than just using the DOM Level 1 HTML properties like element.href= '...';.

bobince
A: 

Its called object caching and it will boost your script performance.
See at http://www.javascriptkit.com/javatutors/efficientjs.shtml for details.
Also, if you change the CSS often i would suggest using jQuery as suggested by @Fahad.

Dror
Does JQuery automatically do object caching for me? If not, seems like my proposed solution is the best answer, no?
TeddyH
That link doesn't apply. It's using document.Images not document.getElementById
Mike Blandford
The idea of not re-searching the DOM each time is what I meant, looking for all images or a specific element by ID illustrates the same idea.
Dror
A: 

No, there would not be a significant performance gain. Your performance problems lie elsewhere. The browser has its own index on element id -> element object.

If you want to find out why your code is slow, it is very important to time it because the slow part is probably not what you'd expect (I've found this out the hard way). You can do so like this:

var t0 = (new Date()).getTime();
var t1 = (new Date()).getTime();
var time = t1 - t0;

Although it's important to note that the accuracy here is 15ms, meaning if something takes 14ms it might show up as 0ms in some browsers.

Here's what your code would look like in jQuery:

$("#desc").attr("href", "#")
    .click(function(){})
    .css("text-decoration", "none");
Mike Blandford
A: 

The short answer is yes, anytime you can make a Javascript variable or object reference local, it will help with performance.

If you'd like a deeper understanding of scope management and its performance implications on Javascript, the Speed Up Your Javascript tech talk has some really good information. Highly recommended viewing.

Sean McMains
A: 

So all the "yes" answers were bugging me, so I actually timed this to see if getElementById was slow!

Here are the results (for a page with 10,000 elements on it):

IE8 getElementById: 0.4844 ms
IE8 id array lookup: 0.0062 ms

Chrome getElementById: 0.0039 ms
Chrome id array lookup: 0.0006 ms

Firefox 3.5 was comparable to chrome.

Half a millisecond per function call isn't going to get me to use an array ;) But maybe it's worse on IE6, which I don't have installed.

Here's my script:

<html>
<head>
<script type="text/javascript">
    var numEles = 10000;
    var idx = {};

    function test(){
     generateElements();
     var t0 = (new Date()).getTime();
     var x = selectElementsById();
     var t1 = (new Date()).getTime();
     var time = t1 - t0;
     generateIndex();
     var t2 = (new Date()).getTime();
     var x = selectElementsWithIndex();
     var t3 = (new Date()).getTime();
     var idxTime = t3 - t2;

     var msg = "getElementById time = " + (time / numEles) + " ms (for one call)\n"
      + "Index Time = " + (idxTime/ numEles) + " ms (for one call)";
     alert(msg);
    }

    function generateElements(){
     var d = document.getElementById("mainDiv");
     var str = [];
       for(var i=0;i<numEles;i++){
        str.push("<div id='d_" + i + "' >" + i + "</div>");
     }
     d.innerHTML = str.join('');
    }

    function selectElementsById(){
     var eles = [];
     for(var i=0;i<numEles;i++){
      var id = ((i * 99) % numEles);
      eles.push(document.getElementById("d_" + id));
     }
     return eles;
    }

    function generateIndex(){
     for(var i=0;i<numEles;i++){
      var id = "d_" + i;
        idx[id] = document.getElementById(id);
     }
    }

    function selectElementsWithIndex(){
     var eles = [];
     for(var i=0;i<numEles;i++){
      var id = ((i * 99) % numEles);
      eles.push(idx["d_" + id]);
     }
     return eles;
    } 
</script>
</head>
<body onload="javascript:test();" >
<div id="mainDiv" />
</body>
</html>
Mike Blandford
Seriously, why is IE so slow! I don't even want to think about how slow IE6 is.
ChaosPandion