Our little programming contest was fun and we can learn something about best practices in javascript algorithm performance. I have prepared some micro benchmarks for common code sniplets to find the best variant. After the section with the micro benchmarks you can find the best-performed solution by running the JSLitmus test and browse through the javascript code. And yes – our co-author Matthias had the best solution with factor 20-35 faster than the clean code variant. No solution is close with the performance to Matthias’ solution!

Knowing some javascript performance hints are importend. The different javascript interpreter with Just-In-Time-Optimizer can offer some surprise in the following basic code examples.

Adding Numbers to an Array

Using code in loop-header or Body

Round down a Number

Using linear Array or Object (=hashmap) for caching Numbers

Find a substring in a String





Adding Numbers to a Array

The clean code solution forced you to use the push-method to add a number to the Array. Is this the best way?

benchArrayPush = function(count) { var a = []; while (count--) a.push(count); }; benchArrayLength = function(count) { var a = []; while (count--) a[a.length] = count; }; benchArrayLocal = function(count) { var a=[], l=0; while (count--) a[l++] = count; }; benchArrayFixedLocal = function(count) { var a=new Array(count), l=0; while (count--) a[l++] = count; };

Array.push is only in Chrome faster than the other variants

Using a local variable as index instead of the Array.length attribute is in opera and FF 3.6 faster

Why is defining a Array with the end length slower than Array.push in Chome?

conclusion: The variant with using

Array.length

has good performance and dont need an extra variable. One point for clean code!





Using code in loop-header

Instead of call all operation in the body of a loop, you can put simple operation in the head of a loop. This is not clean code, but all operation can seperated by a “,”. Is there an optimizer who accept this coding style as performant?

benchLoopHeader = function(count) { var i,j,i1=0,i2=0,i3=0,i4=0,i5=0,i6=0,i7=0,i8=0,i9=0, sum=0; for (j=10;j;j--) for (i=count; i; i1++,i2++,i3++,i4++,i5++,i6++,i7++,i8++,i9++,i--) sum++; }; benchLoopBody = function(count) { var i,j,i1=0,i2=0,i3=0,i4=0,i5=0,i6=0,i7=0,i8=0,i9=0, sum=0; for (j=10;j;j--) for (i=count; i; i--) { i1++; i2++; i3++; i4++; i5++; i6++; i7++; i8++; i9++; sum++; } }; benchLoopLine = function(count) { var i,j,i1=0,i2=0,i3=0,i4=0,i5=0,i6=0,i7=0,i8=0,i9=0, sum=0; for (j=10;j;j--) for (i=count; i; i--) { i1++;i2++;i3++;i4++;i5++;i6++;i7++;i8++;i9++;sum++; } };

conclusion: The loop body solution has no performance problems comparing with the other variants. You can use the clean coding style – second point !





Round down a Number

The

Math.floor

function is defined to round down and

Math.ceil

for rounding up. But are these function the best choice?

benchIntegerFloor = function(count) { var i = 7.7, r; while (count--) r = Math.floor(i); }; benchIntegerParseInt = function(count) { var i = 7.7, r; while(count--) r = parseInt(i); }; benchIntegerParse10 = function(count) { var i = 7.7, r; while(count--) r = parseInt(i, 10); }; benchIntegerBinaryOr = function(count) { var i = 7.7, r; while(count--) r = i|0; };

Using parseInt force the javascript interpreter to cast the Number to a String before parsing – this is slow!

If you use the bitwise OR all browser are very fast to convert it into an 32 bit integer. If your Number is greater than 2^32 the OR-variant will fail.

Conclusion: if your Number range use only 32-bit values (like in the contest) bitwise OR is the fast option, but not clean code. 1 point against clean-code.





Using Array or Object for caching Number results

For the pre-calculated results is an Array the right container as Cache – or is the standard JavaScript Object better?

benchCacheArray = function(count) { var a=[], i, j, c; for (i=count/2; i; i--) a[i]=i; for (i=count/2; i; i--) c = a[i]; }; benchCacheObject = function(count) { var a={}, i, j, c; for (i=count/2; i; i--) a[i]=i; for (i=count/2; i; i--) c = a[i]; };

Opera / Chrome are factor 6 faster than FF while accessing Object or Array!

There is no better performance from FF 3.6 to FF 4

Chrome has optimized the Array access with Numbers

conclusion: Using an Array for cached Number results is Ok, but the hashmap/Object variant is fast, too! Next point for clean code!





Find a substring in a String

What is the fastest method to find a substring in an given String? Many commentators used the

String.indexOf

-method, only one anonymous writer used the

RegExp("7")

constructor.

benchStringMatch = function(count) { var seven = "12734", res; while (count--) res = seven.match(/7/); }; benchStringRegExTest = function(count) { var seven = "12734", res, hasSeven = new RegExp("7"); while (count--) res = hasSeven.test(seven); }; benchStringIndexOf = function(count) { var seven = "12734", res; while (count--) res = seven.indexOf("7")!==1; };

String.match is factor 3 -10 slower than a predefined RegExp Object.

the String.indexOf method is in both Firefox very fast

to find one substring in many Strings the RegExp Object is in Opera / Chrome faster than String.indexOf

conclusion: Find the best variant for your usage. Or use browser-optimized code between FF/Chrome – one point against clean code.





Check the best solution for the game of forfeit















Tipp: Maximize your browser because the javascript code has fixed font width.

clean code in JavaScript

Good news for JavaScript number cruncher. Your performance depends on your algorithm and not on cryptic hacks in JavaScript!