mscir wrote:
<snip>
This one includes a lot of the good advice I've seen posted in this
ng:
http://www.codeproject.com/useritems/JavaScript.asp
<snip>
Scattered among the good advice on that page are a number of
suggestions that bring into question its author's understanding
of javascript. Starting with:-
| Refactor to Simplify Code
| ...
| ... . Here's a simple example that replaces an assignment with an
| initialization. So instead of this:
|
| function foo() {
| var i;
| // ....
| i = 5;
| }
|
| Do this:
|
| function foo() {
| var i = 5;
| // ....
| }
- By ECMA specification I don't see any difference between these two,
so no performance improvement should be expected to follow.
The variable declaration happens during "variable initialisation" upon
entering the execution context in both cases, and the assignment
happens in the loop.
| Minimize DOM Interaction and I/O
|
| Interacting with the DOM is significantly more complicated than
| arithmetic computations, which makes it slower. When the JavaScript
| interpreter encounters a scoped object, the engine resolves the
| reference by looking up the first object in the chain and working
| its way through the next object until it finds the referenced
| property. To maximize object resolution speed, minimize the scope
| chain of objects. Each node reference within an element's scope
| chain means more lookups for the browser. Keep in mind that there
| are exceptions, like the window object, which is faster to fully
| reference. So instead of this:
|
| var link = location.href;
|
| Do this:
|
| var link = window.location .href;
Objects don't really have a scope chain (those belong to function
objects (as an internal property) and execution contexts). And the
- window - reference has no special role, it is a property of the
global object, and, as an identifier, will be resolved at the end
of a function's scope chain, exactly as - location - would. Making
the proposed second property accessor slower than the first.
| Minimize Object and Property Lookups
|
| Object-oriented techniques encourage encapsulation by tacking
| sub-nodes and methods onto objects. However, object-property
| lookups are slow, especially if there is an evaluation. So
| instead of this:
|
| for(var i = 0; i < 1000; i++)
| a.b.c.d(i);
|
| Do this:
|
| var e = a.b.c.d;
| for(var i = 0; i < 1000; i++)
| e(i);
This is a dangerous suggestion to be making given the example. The
expression - a.b.c.d(i) - is a method call (calling a - d - method on
the object referred to by - a.b.c -). Executing it as - e(i) - makes
it into a call to a function object, moving the - this - reference
from the - a.b.c - objet to the global object.
It would have been better to do:-
var e = a.b.c;
for(var i = 0; i < 1000; i++)
e.d(i);
- and keep the - this - reference of the method pointing at the
expected object.
| ...
|
| Also, accessing a named property or object requires a lookup.
| When possible, refer to the object or property directly by
| using an index into an object array. So instead of this:
|
| var form = document.f2; // refer to form by name
|
| Do this:
|
| var form = document.forms[1]; // refer to form by position
If that represents a recommendation to use indexed property accessors
over named ones then it is total rubbish as both will use the same
internal method to evaluate the property accessor, and the indexed
version will involve an additional type-conversion to string and as
a result could be slower (though HTML collections may be optimised
for indexed reference in a way that JS objects probably wont be)).
| Shorten Scope Chains
|
| ...
|
| ... . Each set of brackets
| recursively defines a new child of that scope. ...
Javascript is not block scoped.
| ...
|
| Avoid with Statements
|
| The with statement extends the scope chain temporarily with
| a computed object, executes a statement with this longer
| scope chain, and then restores the original scope chain.
| This can save you typing time, but cost you execution time.
| Each additional child node you refer to means more work for
| the browser in scanning the global namespace of your
| document. So instead of this:
|
| with (document.formn ame) {
| field1.value = "one";
| field2.value = "two";...
| }
|
|
| Do this:
|
| var form = document.formna me;
| form.field1.val ue = "one";
| form.field2.val ue = "two;
|
| Cache the object or property reference instead of using with,
| and use this variable for repeated references. with also
| has been deprecated, so it is best avoided.
This is not true either. The resolution of the property accessors
in the second case will take longer than the ones used in the - with
- statement, because the second version involves resolving - form -
against the scope chain (it will be fond on the first object on the
scope chain) and then resolving - field1 - or - field2 - as
properties of that object, which will take exactly as long as
resolving - field1 - or - field2 - on the first object in the scope
chain in the with - statement version, but the - with - statement
version does not need to resolve - form - first.
If there is a performance difference between the two it must be
entirely down to the overhead of using the - with - statement,
and the significance of that will diminish with an increase in
the number of property accessors/identifier needing to be resolved
within it.
Not that I think that - with - statements should be used, but this
is not an example of a reason for not using them (at least as stated).
| Access NodeLists Directly
|
| NodeLists are lists of elements from object properties like
| .childNodes and methods like getElementsByTa gName(). Because
| these objects are live (updated immediately when the
| underlying document changes), they are memory intensive and
| can take up many CPU cycles. If you need a NodeList for only
| a moment, it is faster to index directly into the list.
| Browsers are optimized to access node lists this way. So
| instead of this:
|
| nl = document.getEle mentsByTagName( "P");
| for (var i = 0; i < nl.length; i++) {
| p = nl[i];
| }
|
| Do this:
|
| for (var i = 0; (p = document.getEle mentsByTagName( "P")[i]); i++)
|
| 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.
I cannot believe that this is true, it implies that it is faster to
create a new nodeList for each iteration of a loop than to create
one before the loop and then just index it in the loop.
It was also interesting to notice:-
| n = parseInt(iterat ions / 8);
- in a page on code optimisation. Math.floor should be faster than
parseInt (and more reliable) in context, and fast division by 8
with an integer result would be quickest as -
n = (iterations>>3) ;
- assuming iterations was known to be of a suitable size.
Richard.