Conditional Benchmarks
As most JavaScript programmers know (and many are all-too familiar with), speed is a major factor when considering how to accomplish any given task. Once in a while, a script will still run too slowly even after standard optimization tricks have been applied. When this happens, it makes sense to revisit common practices to see if they can be improved.
I've noticed that much of the code that I write contains large if blocks and switch statements. Going back and reading what I've written,
I sometimes can't figure out why I chose one method over the other, given that they can both get the same job done. Usually I think readability is a factor, but which method is
more readable is typically subjective, making that irrelevant.
One use case in which if may be an obvious choice is if the conditionals needed do not translate well into a switch. Here's an example:
The above block already lacks a bit in readability, and converting it to switch would be a nightmare.
In this instance, if is the clear choice because of its flexibility. In many cases though, a single variable is being checked in a large set of conditionals.
This is the use case that I wanted to explore.
To me, JavaScript is all about doing things in clever new ways to overcome limitations.
Given that JavaScript is such an expressive, powerful language, is there a different approach that could be taken regarding these conditional blocks?
One method that can be used is what I call an object conditional.
(This concept is not new to the front-end engineering world.)
In the example below I have setup a common, easily readable if block (commented out). After that is the same behavior as described in an object:
You can run this example by pressing the button below:
There are many things to consider here.
The first and most obvious being that the object conditional itself uses an if block, making it seem like it would be slower than the if alone right off the bat.
The only other way to emulate both else and default without getting the error testObject[bro] is not a function
is with a try...catch statement.
Since we all know that catching errors is really slow, that's not an option when we're going for
high performance. So we'll have to settle for using an if.
Something else to consider is that the scope is lost when calling a function, a problem that's not an issue using the other two methods. This is easily solved, however, by passing whatever you'd like into the function call, for example:
testObject[val].call(args, this, etc);
Now that we've got our three different methods, let's find out which is fastest!
This benchmark sets up three different tests, one with if, one with switch, and one using an object conditional.
Each method checks four different values and then falls into the default, for a total of five states.
This is executed 10,000 times to get a good sampling to work with.
You can execute this benchmark yourself below:
Results will vary of course, but I compiled my findings in the table below. Using Windows XP, I ran the tests ten times in each of the common browsers and recorded the averages:
| Browser | if block |
switch statement |
object conditional |
|---|---|---|---|
| Firefox 2 | 444 milliseconds | 425 milliseconds | 310 milliseconds |
| Firefox 3 | 50 milliseconds | 38 milliseconds | 42 milliseconds |
| Google Chrome | 11 milliseconds | 11 milliseconds | 20 milliseconds |
| Internet Explorer 6 | 353 milliseconds | 347 milliseconds | 290 milliseconds |
| Internet Explorer 7 | 375 milliseconds | 381 milliseconds | 344 milliseconds |
| Opera 9.5 | 50 milliseconds | 55 milliseconds | 54 milliseconds |
| Safari 3 | 150 milliseconds | 156 milliseconds | 137 milliseconds |
It looks like the winner in terms of speed is usually the clever contendor, the object conditional. But not by a large margin. There's a lot to be said about code readability, so if using this method will make your application harder to maintain, it may not be worth it. Indeed, my colleague Douglas Crockford (Yahoo!'s JavaScript architect) has good cautionary advice here:
In chosing how to structure a program, the first priority has to be clarity of expression. From clarity comes correctness and maintainability. Subordinating clarity to save milliseconds should be discouraged. That is the wrong motivation.
This is certainly true, but sometimes structure unfortunately needs to take a back seat to performance. The most common use case that comes to my mind is animation.
Say for example, you are implementing an animation that moves an element across the screen and must perform complex calculations over each iteration. Using an animation library like the one YUI provides, the code might look something like this:
Given this example, optimization is critical, and those few milliseconds gained by using a quicker pattern could make the difference between a great user experience and a sluggish one.
What are your thoughts? I look forward to your feedback in the comments section.
Edit 9/02/08: Added Google Chrome.