Posts Tagged ‘Performance’

Partial loop “unrolling”

Posted in 'Code Snippets, JavaScript' by James on November 13th, 2009

In Thomas Fuchs’ latest JavaScript performance presentation he talks about the speed gains that can be experienced by using “unrolled” loops.

A conventional loop:

for (var i = 0; i < 10; ++i) {
    doFoo(i);
}

The “unrolled” version of that loop:

var i = 0;
doFoo(i++); doFoo(i++); doFoo(i++); doFoo(i++); doFoo(i++);
doFoo(i++); doFoo(i++); doFoo(i++); doFoo(i++); doFoo(i++);

A partially unrolled version:

for (var i = 0; i < 10; ) {
    doFoo(i++);
    doFoo(i++);
    doFoo(i++);
    doFoo(i++);
    doFoo(i++);
}

Interestingly, speed gains can be experienced dependent on the loop size, albeit marginal at best. I thought about ways to build this into a clever forEach function and came up with something that ‘pre-compiles’ functions containing partially unrolled loops. Have a look:

var forEach = (function() {
 
    var fns = [],
        callers = "true",
        numberFn = 10,
        i = 1;
 
    for ( ; i <= numberFn; ++i ) {
        callers += "&&f(a[++i])!==false";
        fns[i] = new Function("a", "f", "l", "var i=0;while (i<l) {"+callers+"}");
    }
 
    return function( array, fn ) {
 
        var len = array.length,
            n = numberFn, i;
 
        while (i = n--) {
            if ( len % i === 0 ) {
                return fns[i](array, fn, len);
            }
        }
 
    };
 
})();

This function will run one of 10 ‘pre-compiled’ functions on the passed array, dependent on the highest factor of the array’s length. I’m only creating 10 different functions in this example, you could create more.

If you were to pass an array with a length of 14, then fns[7] would be used, since 7 is the highest available factor (the highest number below 10 that 14 can be divided by, to gain a whole number). fns[7] looks something like this:

function anonymous(a, f, l) {
    var i = 0;
    while (i < l) {
        true &&
            f(a[++i]) !== false &&
            f(a[++i]) !== false &&
            f(a[++i]) !== false &&
            f(a[++i]) !== false &&
            f(a[++i]) !== false &&
            f(a[++i]) !== false &&
            f(a[++i]) !== false;
    }
}

The !== false part is used to create the effect of loop-breaking. Notice that the success of this boolean expression is depended upon to continue the chain of expressions (a && b && c)

I’ve only tested it briefly, and to be honest, there doesn’t seem to be a notable benefit. In IE, I can see a bit of improvement over the conventional forEach implementation but only if I’m using arrays with 1000+ lengths. I think this would only be useful in situations where you absolutely have to squeeze every inch of potential performance out of your app. Anyway, it’s still pretty interesting, I wonder what other fancy things can be created by using pre-compiled functions.

Zakas’ JavaScript performance tips

Posted in 'JavaScript' by James on August 8th, 2009
Zakas’ JavaScript performance tips

Nicholad Zakas, who wrote this book, recently spoke about JavaScript performance at Google; his presentation was called “Speed Up Your JavaScript” and it’s available to view on Youtube.

In the presentation Nicholas covers areas rarely talked about; he takes a low-level approach by explaining what’s happening behind the scenes when you do something as simple as creating or requesting a variable in JavaScript. It’s not all conjecture though; he has a number of graphs comparing performance across browsers and then details the steps you can take to optimise your code, in order to protect yourself from less-than-satisfactory JavaScript implementations (IE comes to mind).

I’m not obsessed about performance by any means but I do think that the practices shared in his presentation should be followed to the letter. Speed and performance are hot topics on the client-side; our users demand fast and responsive applications/websites.

His advice:

Five key points emerged during the presentation:

  • Store out-of-scope variables in local variables.
  • Minimise property access.
  • Do as little as possible on each iteration of a loop.
  • Minimise document reflow by only changing the DOM when absolutely necessary.
  • Don’t use inline styles unless you’re animating.

Store out-of-scope variables in local variables

The idea behind this technique is to minimise the amount of work required to get at the variable you want. The further away it is (in the scope chain) the longer it’s going to take to retrieve it. The performance cost is normally marginal but it’s still a good practice. Here’s an example:

Asynchronous innerHTML

Posted in 'Code Snippets, JavaScript' by James on April 25th, 2009

A recent question on Stack Overflow posed a common question concerning DOM insertion and specifically the dire performance of IE6 when using innerHTML to parse a large amount of HTML markup. Head over there to read the question for yourself. I thought it worth sharing my solution; an asynchronous function to add large quantities of HTML to a page without locking up the browser:

function asyncInnerHTML(HTML, callback) {
    var temp = document.createElement('div'),
        frag = document.createDocumentFragment();
    temp.innerHTML = HTML;
    (function(){
        if(temp.firstChild){
            frag.appendChild(temp.firstChild);
            setTimeout(arguments.callee, 0);
        } else {
            callback(frag);
        }
    })();
}

The large amount of HTML, on its own, is no problem; it’s adding it to the DOM which creates a delay. To avoid this, the HTML is first added to an outside-of-DOM div, the child nodes of which are then recursively added to a document fragment. The fragment is passed to the callback for insertion – or whatever else you may want to do.

The timeout of zero is just to let the browser catch a breath before continuing; doing so means that the user can continue to interact with the page while this all occurs.

Here’s an example:

var htmlStr = '<div><p>...</p><p>...</p><div><div>...</div>';
asyncInnerHTML(htmlStr, function(fragment){
    // You can treat 'fragment' as a regular node.
    document.body.appendChild(fragment);
});

Really easy speed testing

Posted in 'Code Snippets, JavaScript' by James on April 19th, 2009

Earlier today, out of sheer curiosity, I wanted to find out the quickest method of duplicating an array in JavaScript. The different methods I tested included:

  • Calling the array’s slice method, passing 0:
    originalArray.slice(0);
  • Creating a new array, applying the entire original array:
    Array.apply(Array, arrayToDuplicate);
    // Shorter version of:
    // (new Array()).apply( new Array(), originalArray);
  • Looping through the original array, copying one by one:
    var duplicate = [];
    for (var i = 0, len = originalArray.length; i < len; i++) {
        duplicate[duplicate.length] = originalArray[i];
    }

Note that none of the above methods perform a “deep copy” so any “pass-by-reference” values within the original array will not be copied, just referenced from within the duplicate array. Also note that, in this post, when I refer to a “method” I may just be referring to a regular function.

To perform this test I constructed a basic speed-testing class, and that is what I’m sharing with you today:

function SpeedComparison(testData, accuracy, methods) {
    if ( ! (this instanceof arguments.callee) ) { return; }
    this.accuracy = accuracy || 1000;
    this.methods = methods || {};
    this.testData = testData;
    this.results = {};
}
 
SpeedComparison.prototype = {
    addMethod : function(name, method) {
        this.methods[name] = method;
        return this;
    },
    removeMethod : function(name) {
        delete this.methods[name];
        return this;
    },
    begin : function() {
        iterateMethods : for (var method in this.methods) {
            var sTime = +new Date();
            for (var i = 0, a = this.accuracy; i < a; i++) {
                if (this.methods[method](this.testData) === false) {
                    this.results[method] = 'Failed';
                    continue iterateMethods;
                }
            }
            var fTime = +new Date();
            this.results[method] = fTime - sTime;
        }
    }
};

The SpeedComparison constructor accepts three parameters:

  • testData – whatever you pass here is passed to each method you specify (each method to be compared).
  • accuracy – this is the number of times the different methods will be compared, i.e. how many times each method is run.
  • methods – an object containing all of the methods to be compared.

All parameters are optional and can be added/changed later via their respective properties.

An example

Here’s how I tested the different methods of duplicating an array (discussed earlier):

var testArray = ['a', 'very', 'big', 'array', 'etc.'];
var arrayCopyTest = new SpeedComparison(testArray, 5000);
 
// Add each method to be tested:
arrayCopyTest.methods = {
    'Slice' : function(testData) {
        testData.slice(0);
    },
    'New Array' : function(testData) {
        Array.apply(Array, testData);
    },
    'Loop' : function(testData) {
        var ret = [];
        for (var i = 0, len = testData.length; i < len; i++) {
            ret[ret.length] = testData[i];
        }
    }
};
 
arrayCopyTest.begin();
 
console.log (arrayCopyTest.results);
 
// "arrayCopyTest.results" shows all methods' times - lower is better.

For those interested, here are the results from that test:

“Slice” (ms) “New Array” (ms) “Loop” (ms)
Firefox 3 15 24 103
IE 7 250 219 484
Chrome 23 7 15
Safari 4 25 9 23

Interestingly, in all browsers other than Firefox, the 2nd method performs the best:

Array.apply(Array, originalArray);

The speedComparison class is useful for quick n’ dirty speed checks like this.

Right now, it only gives you the times (in milliseconds), but the results could easily be extended via the prototype. I know that more sophisticated means exist to perform such tests; I just needed something simple and functional to conduct a few small speed comparisons.