2006-01-18

Efficient code branching in javascript

First off: default optimization rules still apply. Lots of time and code readability is wasted on optimizations that does not speed up, or save memory, for applications to any measurable degree. Don't go there unless that extra bit of efficiency is really needed, in which case you should do measurements to track down hot spots, addressing those. Read through the slides on optimization from What Works in Software Development (via The Farm), for instance, if you are unfamiliar with when, where and how to do optimization.

Indeed, instead of seeing this as a tip on optimization, see this post more as a way of breaking free of programming style baggage you might have acquired in programming largely compile time static environments such as Java, where the compile time reality and looks of methods is set in stone. Javascript is, by contrast, a very dynamic language, and there are benefits to reap stemming from that fact.

Most javascript code today doing anything even remotely advanced with the DOM needs to be aware of the different ways of solving the same problems in different browsers. The IE reality is a harsh one in ways that its Mozilla or Opera counterparts are not, for instance, and depending on what you do, it might need doing somehow else for Safari to cooperate, and so on. So it has some kind of browser forking, executing different code in different browsers.

The approach is typically this: make a method that does Something. Prior to making this Something, test for which browser environment is running the code, and pick a code branch depending on the outcome. And the tip is just as simple: as you know that during the execution time of your script, the target browser will be the same browser exhibiting the same flaws as it was the first time you tested it, you may opt to do this test once, rather than every time your method is invoked. In effect, you customize your methods in an initialization step that sets up the code to run in the way the visiting browser wants it, and get rid of the excess code and testing baggage that would have allowed other execution paths for other browsers.

An example, testing for an archaic pre-DOM browser from Microsoft to implement one of the most frequently typed DOM methods, typically called something offensively long:
function $( id )
{
if( document.getElementById )
return document.getElementById( id );
if( document.all )
return document.all[id];
}

The exact same behaviour, minus the run-time testing overhead, could be expressed as:
if( document.getElementById )
$ = function( id ){ return document.getElementById( id ); };
else if( document.all )
$ = function( id ) { return document.all[id]; };
else
$ = function(){ return undefined; };

You should also be aware that this, like any other possible optimization, might not always end up a speedup, even if it runs in some inner loop hot spot of your code. It could even slow down the code; measure, measure, measure! A bit of inlined bulky code testing for and calling document.getElementById directly when available, in every bit of code in your application that picks up a node by its id, might prove very much faster than the additional invocation of a javascript function. You won't know until you measure it in all the target environments it is supposed to run in. Which again should remind you of how expensive optimization can be, in terms of development time.

But it does not hurt knowing your options when you write code that needs branching in ways you could test for in advance, or the first time it gets invoked only, rather than every time it gets run.
blog comments powered by Disqus