Optimizing Javascript

6 views
Skip to first unread message

Nick Tulett

unread,
Oct 7, 2009, 8:30:17 AM10/7/09
to Make the Web Faster
Wouldn't evaluating foo.length in every pass through a for loop (as in
the examples) be the number one cause of inefficiency?

Dan Johansson

unread,
Oct 7, 2009, 11:43:16 AM10/7/09
to make-the-...@googlegroups.com
I don't know the internals of the language. But my guess would be probably not.

Array and Strings are objects of which length is a member. Its unlikely that length is getting recalculated every time its accessed. Instead its calculated when an event occurs that changes that. Such as removing or adding an element to the array.

Greg Schechter

unread,
Oct 7, 2009, 12:05:16 PM10/7/09
to Make the Web Faster
Depending on the specific example it might not be the number one
inefficiency, but changing it so foo.length is only calculated once
will save time. See this page for some tests.
http://blogs.sun.com/greimer/resource/loop-test.html

Erik Arvidsson

unread,
Oct 8, 2009, 2:08:38 PM10/8/09
to Make the Web Faster


On Oct 7, 9:05 am, Greg Schechter <diabolomas...@gmail.com> wrote:
> Depending on the specific example it might not be the number one
> inefficiency, but changing it so foo.length is only calculated once
> will save time. See this page for some tests.http://blogs.sun.com/greimer/resource/loop-test.html
>
> On Oct 7, 5:30 am, Nick Tulett <nicktul...@yahoo.com> wrote:
>
>
>
> > Wouldn't evaluating foo.length in every pass through a for loop (as in
> > the examples) be the number one cause of inefficiency?

Depends on what the collection is. If it is an Array or a JS string
getting the length is O(1) and of negligible time compared to say a
DOM property lookup.

Introducing a variable with the length will not make the loop slower
but it makes the code larger and sometimes less readable.

Nick Tulett

unread,
Oct 9, 2009, 3:16:57 AM10/9/09
to Make the Web Faster
On Oct 8, 7:08 pm, Erik Arvidsson <erik.arvids...@gmail.com> wrote:

> Introducing a variable with the length will not make the loop slower
> but it makes the code larger and sometimes less readable.

Not entirely convinced by the readability argument:
a. Anyone who can't understand a properly formed for loop probably
shouldn't be writing javascript - there is no compiler optimising your
code for you.
b. You would hope that your code is executed by machines far more
times than it is read by humans, so optimising for developers is
misdirected effort.

Justin Johnson

unread,
Oct 9, 2009, 5:35:56 AM10/9/09
to Make the Web Faster
Since there is some scope chaining that has to be walked, it's mildly
inefficient, but not really the biggest kicker. People newer to the
language usually fall into querying the DOM for the same objects every
pass through a loop, such as

for ( var i=0; i<magic; i++ ) {
var container = document.getElementById("some-id");
// do stuff with container
}

instead of

var container = document.getElementById("some-id");
for ( var i=0; i<magic; i++ ) {
// do stuff with container
}

On Oct 7, 5:30 am, Nick Tulett <nicktul...@yahoo.com> wrote:

niklasr

unread,
Oct 11, 2009, 4:34:17 PM10/11/09
to Make the Web Faster


On Oct 7, 12:30 pm, Nick Tulett <nicktul...@yahoo.com> wrote:
> Wouldn't evaluating foo.length in every pass through a for loop (as in
> the examples) be the number one cause of inefficiency?
Iterating twice what one iteration can is inefficiency waste often
registered, first iteration in app layer for instance, get list from
datalayer, then iterate clientside for no reason what is feasible in 1
iteration often since different teams are serverside, generating kml
or likewise to javascripters adding effects 2nd iteration. Browsing
with the links browser textonly is superfast bypassing all smiling
faces and glossy heavy graphics nobody needs resulting fastest
browsing from cheapest client>
links.sourceforge.net

strife25

unread,
Nov 5, 2009, 1:37:26 PM11/5/09
to Make the Web Faster
Coming from other languages one would consider the following line of
code to return an array/list/object of the query:

var x = document.getElementsByClass("foo");

And would move on to do property lookups of the variable x e.g.

x.length === 10

Unfortunately, this is not good to do in javascript since functions
are are also objects. In javascript, what is actually occurring is
the FUNCTION of "document.getElementByClass("foo") into the variable
x. So instead of a quick property lookup when getting the length of
x, 2 steps are occurring:

1.query the page for all nodes that have the class "foo"
2. get the amount of the nodes that were found.

Combine this in a for-loop:

var x = document.getElementsByClass("foo");
for( var i=0; i < x.length; i++){
//do stuff
}

on EACH LOOP we run the query AND the property lookup, instead of just
getting a value of the amount of nodes found.

Considering this, the following should be the method used:

var x = document.getElementsByClass("foo");
length = x.length;
for( var i=0; i < x.length; i++){
//do stuff
}

Now the DOM query occurs once.

This is one of the reasons that the DOM sucks and is a tricky thing to
find out because it's not what most other languages do.

Amr Mostafa

unread,
Nov 6, 2009, 10:19:23 AM11/6/09
to Make the Web Faster
On Nov 5, 8:37 pm, strife25 <trippinbill...@gmail.com> wrote:
> var x = document.getElementsByClass("foo");
>
> And would move on to do property lookups of the variable x e.g.
>
> x.length === 10
>
> Unfortunately, this is not good to do in javascript since functions
> are are also objects.  In javascript, what is actually occurring is
> the FUNCTION of "document.getElementByClass("foo") into the variable
> x.  So instead of a quick property lookup when getting the length of
> x, 2 steps are occurring:
>
> 1.query the page for all nodes that have the class "foo"
> 2. get the amount of the nodes that were found.

Any references to back that?

Andrew Hedges

unread,
Nov 6, 2009, 2:45:45 PM11/6/09
to Make the Web Faster
> on EACH LOOP we run the query AND the property lookup, instead of just
> getting a value of the amount of nodes found.

That's incorrect. The value of x is the return value from
document.getElementsByClass("foo"). Sure, functions can return
functions, but in this case, the return value is a node list. There
may be other reasons not to do this in this way, but the argument that
a function is going to be executed each time x.length is referenced is
not one of them.

Regards,
-Andrew
---
and...@hedges.name / http://andrew.hedges.name/

Kiwi

unread,
Nov 8, 2009, 7:21:50 AM11/8/09
to Make the Web Faster
> > on EACH LOOP we run the query AND the property lookup, instead of just
> > getting a value of the amount of nodes found.
>
> That's incorrect. The value of x is the return value from
> document.getElementsByClass("foo"). Sure, functions can return
> functions, but in this case, the return value is a node list. There
> may be other reasons not to do this in this way, but the argument that
> a function is going to be executed each time x.length is referenced is
> not one of them.

Question 1/ Is myList.length [for NodeList and for Array] executing a
whole lot of code before giving me the value ?

Yes, functions can return functions, but this is not the case here,
but still a whole lot of code can still be executed before you have
your value.

The function getElementsByName (or Class, or TagName, or Selector, or
whatever existing or forthcoming DOM function doing the same thing)
returns a NodeList Object.

Looking at NodeList in the W3C DOM definition (http://www.w3.org/TR/
REC-DOM-Level-1/level-one-core.html#ID-536297177)
<quote>The NodeList interface provides the abstraction of an ordered
collection of nodes, without defining or constraining how this
collection is implemented.</quote>

So no one [except studying all possible browsers' code in depth] can
in fact tell what's exactly happening under the hood, and shoud not
even bother.

Array.length has the same thing going on, you now - on a scripting
level - that the value changes when the size of the array changes, but
it depends on the implementation internals, and you should never rely
on it being coded one way or another.

Remember objects are pretty complex things, even if in JS many people
tend to mainly use them as single dictionaries, they can do a lot
more.

The thing here is the difference between member variables and member
properties:
- variables store values, and when the variable is accessed, the value
is returned, they are really just allocated memory slots, no code
except assigning or accessing the value in memory
i.e. o.a will only return the value stored in the memory.

- properties are a language conveniences for wrapping usually two
methods [a getter and a setter] (one if read-only or write-only), this
time when you access or write into the property, some code is
executed, instead of just returning the value in memory
i.e. o.b will compute, and could even have to make a synchronous JSON
call, a user prompt or any other heavy computation before giving a
value back

Using properties (and if they are nor widely used in JS, they are in
some high level Object Oriented Languages), one could create a length
implementation that will compute length on each access, or only the
first time it is accessed, or just return the value stored that would
be modified by list modifications.

Enclosed are two test cases, one with getElementsByName, one with a
property definition.

So when not sure if what you access is a property and a value, and if
you rely on it not changing, you could potentially store it in a local
variable.

Remember though that accessing myList[n] is equivalent to myList.item
(n) (this is for DOM), and if the browser's implementation is such
that length always performs the query, it will probably do so for
getting the item too, so you will come from calculating 2*n the list
(one for length, one for item per iteration) to only n+1 computations,
which algorithmically is still O(n), so not much difference.

Working back on the main algorithm to avoid looping through DOM
queries is a much better improvement, but is harder to achieve.

++
Julien

-----Test cases

Here is a test case (tested in IE [5.5, 6, 7, 8, 8 Compatibility],
Safari 4 Windows, Chrome 3, Firefox 3, Opera 9):
This test case shows that on all major browsers, the value of the
length property of a NodeList updates when nodes are created.
------
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/
TR/html4/strict.dtd">
<TITLE>Nodelist autorefresh feature</TITLE>
<SCRIPT LANGUAGE="javascript">
function addEventHandler(element, eventName, handler) {
if(element.addEventListener) {
element.addEventListener(eventName, handler, false);
} else if(element.attachEvent) {
element.attachEvent('on' + eventName, handler);
}
// Browsers managing neither addEventListener nor attachEvent are
outside the scope of this test
}

var globalElements = document.getElementsByName("myName");
var globalCount = globalElements.length;
function countElements(eventArgs) {
if(! eventArgs) {
eventArgs = event;
}
if(eventArgs) {
if(eventArgs.preventDefault) {
eventArgs.preventDefault();
} else {
eventArgs.returnValue = false;
}
}
var localElements = document.getElementsByName("myName");
var text = "GlobalElements: " + globalElements.length + " /
globalCount: " + globalCount + " / LocalElements: " +
localElements.length;
var newElement = document.createElement("A");
newElement.setAttribute("NAME", "myName");
newElement.setAttribute("HREF", "#");
if(newElement.getAttribute("NAME") != "myName") {
// IE < 8 buggy setAttribute support
newElement = document.createElement('<A NAME="myName" HREF="#"/>');
}
addEventHandler(newElement, 'click', countElements);
newElement.appendChild(document.createTextNode(text));
document.body.appendChild(newElement);
document.body.appendChild(document.createElement("BR"));
}
addEventHandler(window, 'load', countElements);
</SCRIPT>
------


Here is a test case (tested in Safari 4 Windows, Chrome 3, Firefox 3,
Opera 9 [Only IE doew not support JScript properties]):
This test case shows that defining a property may not do simple
variable assignment and can do computation on each access.
--> https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Creating_New_Objects/Defining_Getters_and_Setters
------
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/
TR/html4/strict.dtd">
<TITLE>JavaScript Property Support</TITLE>
<SCRIPT LANGUAGE="javascript">
var o = {
a: 5,
get b() {
return this.a > 5 ? "greater" : "lower";
},
set b(x) {
if(! isNaN(Number(x))) {
this.a = x * 2;
} else {
alert("please type a number, current type " + typeof(x));
}
}
};
alert("o.a = " + o.a + "\r\no.b = " + o.b);
o.a = 10;
alert("o.a = " + o.a + "\r\no.b = " + o.b);
o.b = 2;
alert("o.a = " + o.a + "\r\no.b = " + o.b);
o.b = 3;
alert("o.a = " + o.a + "\r\no.b = " + o.b);
o.b = "toto";
alert("o.a = " + o.a + "\r\no.b = " + o.b);
</SCRIPT>

Kiwi

unread,
Nov 8, 2009, 7:39:27 AM11/8/09
to Make the Web Faster
> Wouldn't evaluating foo.length in every pass through a for loop (as in the examples) be the number one cause of inefficiency?

Question 2/ Is accessing an object's property [or variable] on each
iteration slower than storing the value once for all the iterations ?

Yes, accessing an object member (either property or variable) is
slower than accessing a variable.

Accessing an object member, in the interpretor terms is:
- finding the object in memory (walking through the run time scope for
finding it)
- going through all the object's members, prototype and inherited
prototypes searching for a matching member
- getting the value of that member (computing it if this is a
property)

Accessing a variable, in the interpretor terms, is:
- finding the variable in the scopes
- getting the value (and since this is a variable, you know you won't
compute it everytime)

One less step for getting the value, so necessary faster.

From this point on this is all a matter of scope: declaring a variable
as close as possible (in terms of code scope) to where it is going to
be used is most probably going to be faster.
e.g. Take the fact of calling someone from your office phone: if this
is someone you call really often, you will probably have their number
in quick dial, if they work in the same office, you will have a short
internal number for calling them, if they live in the same area, you
won't have to dial the state prefix, and if they are in the same
country you won't dial the +xx country prefix.

Interpretors work pretty much the same, the closest a variable is
declared, the fastest it will be accessed.

Like for '.length' implementation details, all this is browser
internals, so don't take this for granted, maybe some day someone will
make an optimized browser that will precompute the paths for getting
the object's members and it will be as fast as accessing a local
variable, or will have an execution scope dictionary storing all the
variable in constant access time.

You can do this in heavily used loops, but this makes reading the code
sometimes more difficult, and in a production environment, you wan to
be easily aware of what can happen.

> Depending on the specific example it might not be the number one
> inefficiency, but changing it so foo.length is only calculated once
> will save time. See this page for some tests.http://blogs.sun.com/greimer/resource/loop-test.html

It does save time, but I usually don't code loops that don't do
anything but just looping, they often do stuff inside, so the raw
results of executing thousands of empty loops does not imply this is
the major leak.

> var x = document.getElementsByClass("foo");
> length = x.length;
> for( var i=0; i < x.length;  i++){
>     //do stuff
>
> }
>

Please declare everything in the loop declaration, makes the scope
clearer:
for(var i = 0, l = x.length; i < l; ++i) {
// do stuff with x[i]
}

> Now the DOM query occurs once.
>
Not necessarily, since you will access x[i], as for the variable/
property problem, you may ruin the query on every iteration still.
++
Julien

Kiwi

unread,
Nov 8, 2009, 7:42:28 AM11/8/09
to Make the Web Faster


On Oct 7, 1:30 pm, Nick Tulett <nicktul...@yahoo.com> wrote:
> Wouldn't evaluating foo.length in every pass through a for loop (as in
> the examples) be the number one cause of inefficiency?

Question 3/ Is accessing myList.length the number one cause of
inefficiency in JS coding ?

I'd say no, but this is my opinion and is strictly no proof.

JS is often used by site designers that have no experience in
application development, or seen as the last "non important" part of
the application.

The ease of use, ease of development, fast results, broad reach, high
penetration rate, and low investment necessary for developing nice
looking HTML + JS applications makes it a tremendous development
platform, but the lack of common application support [just see how
uneasy it is to support the 4 or 5 major browsers] , the poorness of
debugging and development environment (lack of coding rules, debugging
consoles, performance analyzers, ...), the lack of industrialized
solutions are some the major drawback.

Lately major players in the application development community have
started to move towards more Javascript, and libs such as jQuery are
raising the level, giving developers tools to help them not
reinventing the wheel every time necessary.

JavaScript development should move to being a real development
subject, and not only a thing left for the developers to discover by
themselves, understanding the basics of algorithm optimization and
complexity should be considered a prerequisite for "efficient"
javascript development.

So concerns such as maintenance and readability should sometimes be
taken into account before just optimizing a code to win these few
cycles.

If your concern is about pure efficiency, think about making C/C++ or
even Assembly based plugins, this is way more expensive (possibly one
development per browser per platform), makes the maintenance effort
grow a lot, but it can be blazingly fast.

++
Julien

Sam Foster

unread,
Dec 8, 2009, 5:21:16 AM12/8/09
to Make the Web Faster
> Please declare everything in the loop declaration, makes the scope
> clearer:
> for(var i = 0, l = x.length; i < l; ++i) {
>         // do stuff with x[i]
>
> }

Jumping in at random, (hi new group) the scope is the same here
whether you put the var outside the for block or inside; javascript
doesnt have block scope, the scope is provided by the enclosing
function. Having a local variable in a close to the loop to avoid
walking up the scope chain, and avoiding repeated property lookup
makes a small difference that is sometimes measurable. Personally, the
day I can prioritize loop optimization as being my #1 performance
problem is the day I hang up my hat

/Sam
Reply all
Reply to author
Forward
0 new messages