Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript performance hit for returning a function from a self-executing function?

In firefox there seems to be a big performance difference between the following two functions:

var n1 = 12;

var add1 = function(n2){
    return n1 + n2;
}

var add2 = (function(){
    return function(n2){
            return n1 + n2;
    }
})();

I thought this must be down to the introduction of another level of scope, so created a third example with the variable cached one level up. But this shows an even greater reduction (80%!)

var add3 = (function(){
    var cn1 = n1;
    return function(n2){
            return cn1 + n2;
    }
})();

I would have thought that the closure here would close the performance gap, not enlarge it. Does anybody have an idea what is going on here?

jsPerf test page: http://jsperf.com/variable-scope-speed

like image 764
robC Avatar asked Aug 24 '12 13:08

robC


1 Answers

Its interesting, but my little testing here seems to confirm my earlier assumption, that is, the jsPerf environment influences scopes and scope-chain look-ups itself. I didn't digg into the "how" and "why", but this is my little testscript:

var n1 = 12;

var add1 = function(n2){
        return n1 + n2;
}

var add2 = (function(){
        return function(n2){
                return n1 + n2;
        }
})();

var add3 = (function(){
        var cn1 = n1;
        return function(n2){
                return cn1 + n2;
        }
})();

var add4 = function( n2, n1 ) {
    return n2 + n1;
}.bind(null, n1);


var tests = [add1, add2, add3, add4],
    start, stop, loops;

tests.forEach(function( fnc ) {
    loops = 100000;

    start = Date.now();
    while( loops-- ) {
        fnc( 2 );
    }
    stop = Date.now();

    console.info('Method ', fnc.name || fnc.toString(), ': ', stop - start, ' ms.');
});

And the results on my FireFox 14 look like so:

Method add1: 570ms.
Method add2: 566ms.
Method add3: 414ms.
Method add4: 479ms.

Latest Chrome results:

Method add1: 199ms.
Method add2: 136ms.
Method add3: 85ms.
Method add4: 144ms.

Which definately looks more reasonable. A closured scope-chain lookup has to be always faster, simply for the fact that there is a shorter lookup-chain. Even if all modern browsers don't normally do a classic scope chain lookup, I'm aware of that. Anyway, since browsers create pretty clever lookup tables for free (or out-of-scope) variables, all results should at least be the same. It doesn't make any sense to over-optimize the global object access IMO.

As you noticed, I created one additional test-case for a bound method.

like image 73
jAndy Avatar answered Oct 15 '22 19:10

jAndy