Monday, May 19th, 2008
Some more JavaScript performance tips
<p>Thierry Schellenbach has written up some thoughts about JavaScript optimization for Prototype apps after playing withconsole.profile() / console.profileEnd() in his Prototype applications.
The core advice is pretty simple:
- Beware of $$ and event binding
- Beware of other Prototype methods (reports a 40 times speed different between innerHTML and element.update)
- Write to innerHTML instead of using document.createElement
- Use for loops instead of for in loops
- Use Array.join instead of += on a string
- Cache variables and functions
- Limit the usage of eval
- Limit the usage of Try Catch statements
- When manipulating the DOM copy the element out of DOM change it and stick it back in
We need more performance data on some of these, especially to track them over time. I have seen the opposite argued for a couple of them ;)








I would also warn about using innerHTML. Prototype’s Element#update method isn’t a straight pointer to innerHTML. It fixes a lot of cross-browser issues. Be sure you are not using innerHTML with elements like tables or some other situations because IE and Opera have problems with them.
- JDD
Also Prototype’s new Element(‘div’) should be faster than Element.extend(document.createElement(‘div’)) because it uses cloneNode().
- JDD
Also you can try using the “_each” method on arrays instead of the “each” to avoid the use of the try catch and setting the context.
-JDD
Yes, innerHTML is dangerous issue (for the performance)
Element#update() also evaluates scripts that are injected into the document, that would otherwise be ignored by setting innerHTML.
Echoing Dion’s subtle hint:
http://www.sitepen.com/blog/wp-content/uploads/2008/05/stringfor.png
Specifically at the core advice “Use Array.join instead of += on a string” was directly contradicted by the data I collected during the string performance analysis I wrote about; the link above shows clearly that += beats out both using Array.join and String.prototype.concat on all major browsers.
@ttrenka
Array.join is a lot faster on IE6 that is why it is used. But as as IE6 share decreases, javascript developers should take note and update their code accordingly. Otherwise people will continue to do it for no reason. It’s kind of like how a lot of javascript developers still put a html comment inside of there script tags still. There is no reason to do it anymore.
1) In the UIZE Framework, the Uize.Node.injectHtml static method also deals with evaluating the otherwise crippled scripts, and provides six injection modes: “inner bottom”, “inner top”, “outer bottom”, “outer top”, “inner replace”, and “outer replace”.
2) On the speed of for…in iteration for arrays, don’t use for…in for array iteration. It’s EEEEEEEEVILLLLL! Running a counter with an iterator variable is vastly more efficient. There are times when it’s worth reducing code size by a few characters, and there are times when it’s not. (see http://www.uize.com/tests/performance/array-iteration-styles.html)
3) For additional performance with the counter approach to array iteration, storing the value of the .length property in a local variable also helps (as long as the array will not be modified in length during the operation). Repeated dereferencing of the length property of the array object costs a bit.
On the string concatenation point, Firefox is well optimized for building large strings using +=, while IE is most decidely not. When building large strings (like serializing JSON, XML, or building HTML for a widget), Array.join is the clear winner in IE for building large strings, while it’s mostly a wash in FF (see http://www.uize.com/tests/performance/string-concatenation-approaches.html)
You can checkout this application I put together to see how different calls in JavaScript perform on different browsers.
http://www.rockstarapps.com/samples/performance/
@jdalton -
In regards to cloneNode, I used to think the same thing…then I tested it. cloneNode on a cache object inside a function is slower than createElement due to the overhead of the function call & the object hash lookup. Prototype -may- be getting a bit of a speed bump by using coneNode in new Element() since the function call has already been done, but that speed gain is -very- small and is greatly trumped by the overhead of the rest of the function. In general what I’ve realized is that cloneNode on a SINGLE node is almost never worth it (as of IE7, Safari3, FF2)
thanks for posting this and commenting, appreciate your input a lot guys.
John.