简体   繁体   中英

Is it faster access an javascript array directly?

I was reading an article: Optimizing JavaScript for Execution Speed

And there is a section that says:

Use this code:

for (var i = 0; (p = document.getElementsByTagName("P")[i]); i++)

Instead of:

nl = document.getElementsByTagName("P");

for (var i = 0; i < nl.length; i++)
{
    p = nl[i];
}

for performance reasons.

I always used the "wrong" way, according the article, but, am I wrong or is the article wrong?

"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil."

-- Donald Knuth


Personally i would use your way because it is more readable and easier to maintain. Then i would use a tool such as YSlow to profile the code and iron out the performance bottlenecks.

Good question - I would assume not calling the function getElementsByTagName() every loop would save time. I could see this being faster - you aren't checking the length of the array, just that the value got assigned.

var p;
var ps = document.getElementsByTagName("P");

for (var i = 0; (p=ps[i]); i++) {
  //...
}

Of course this also assumes that none of the values in your array evaluate to "false". A numeric array that may contain a 0 will break this loop.

If you look at it from a language like C#, you'd expect the second statement to be more efficient, however C# is not an interpreter language.

As the guide states: your browser is optimized to retrieved the right Nodes from live lists and does this a lot faster than retrieving them from the "cache" you define in your variable. Also you have to determine the length each iteration, with might cause a bit of performance loss as well.

Interpreter languages react differently from compiled languages, they're optimized in different ways.

Interesting. Other references do seem to back up the idea that NodeLists are comparatively heavyweight.

The question is ... what's the overhead? Is it enough to bother about? I'm not a fan of premature optimisation. However this is an interesting case, because it's not just the cost of iteration that's affected, there's extra overhead as the NodeList must be kept in synch with any changes to the DOM.

With no further evidence I tend to believe the article.

No it will not be faster. Actually it is nearly totally nonsense since for every step of the for loop, you call the "getElementsByTagName" which, is a time consuming function.

The ideal loop would be as follows:

nl = document.getElementsByTagName("P");

for (var i = nl.length-1; i >= 0; i--)
{
    p = nl[i];
}

EDIT: I actually tested those two examples you have given in Firebug using console.time and as everyone have though the first one took 1ms whereas the second one took 0ms =)

It is worthless to discuss theory when actual tests will be more accurate, and by comparing both the second method was clearly faster.

Here is sample code from a benchmark test

var start1 = new Date().getTime();
for (var j= 0; j < 500000; j++){
   for (var i = 0; (p = document.getElementsByTagName("P")[i]); i++);
}
var end1 = new Date().getTime() - start1;

var start2 = new Date().getTime();
for (var j= 0; j < 500000; j++){
    nl = document.getElementsByTagName("P");

    for (var i = 0; i < nl.length; i++)
    {
       p = nl[i];
    }
}
var end2 = new Date().getTime() - start2;

alert("first:" + end1 + "\nSecond:" + end2);

In chrome the first method was taking 2324ms while the second took 1986ms.

But note that for 500,000 iterations there was a difference only 300ms so I wouldn't bother with this at all.

It makes sense to just assign it directly to the variable. Probably quicker to write as well. I'd say that the article might have some truth to it.

Instead of having to get the length everytime, check it against i, and then assign the variable, you simply check if p was able to be set. This cleans up the code and probably is actually faster.

I typically do this (move the length test outside the for loop)

var nl = document.getElementsByTagName("p");
var nll = nl.length;
for(var i=0;i<nll;i++){
    p = nl[i];
}

or for compactness...

var nl = document.getElementsByTagName("p");
for(var i=0,nll=nl.length;i<nll;i++){
    p = nl[i];
}

which presumes that the length doesn't change during access (which in my cases doesn't)

but I'd say that running a bunch of performance tests on the articles idea would be the definitive answer.

The author of the article wrote:

In most cases, this is faster than caching the NodeList. In the second example, the browser doesn't need to create the node list object. It needs only to find the element at index i at that exact moment.

As always it depends. Maybe it depends on the number of elements of the NodeList. For me this approach is not safe if the number of elemets can change, this could cause and index out of bound.

From the article you link to:

In the second example, the browser doesn't need to create the node list object. It needs only to find the element at index i at that exact moment.

This is nonsense. In the first example, the node list is created and a reference to it is held in a variable. If something happens which causes the node list to change - say you remove a paragraph - then the browser has to do some work to update the node list. However, if your code doesn't cause the list to change, this isn't an issue.

In the second example, far from not needing to create the node list, the browser has to create the node list every time through the loop , then find the element at index i. The fact that a reference to the node list is never assigned to a variable doesn't mean the list doesn't have to be created, as the author seems to think. Object creation is expensive (no matter what the author says about browsers "being optimized for this"), so this is going to be a big performance hit for many applications.

Optimisation is always dependant on the actual real-world usage your application encounters. Articles such as this shouldn't be seen as saying "Always work this way" but as being collections of techniques, any one of which might, in some specific set of circumstances, be of value. The second example is, in my opinion, less easy to follow, and that alone puts it in the realm of tricksy techniques that should only be used if there is a proven benefit in a specific case.

(Frankly, I also don't trust advice offered by a programmer who uses a variable name like "nl". If he's too lazy to use meaningful names when writing a tutorial, I'm glad I don't have to maintain his production code.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM