Archive for category Performance

Performance Concerns for Nested JavaScript Functions

Since I dabbled quite a bit in functional languages like Haskell, I came to like nested functions very much.

Searching on the net, I came across many posts and stackoverflow answers claiming that this has a performance impact since a function nested inside another has to be recreated every time the outer function is called.

After talking to my colleagues who assured me that this is not true, at least not for nodejs and chrome (both of which use the v8 JavaScript engine), I decided to find out for myself.

Simple Test

(source on github)

var calls = 99999999;

function notNested() {
    var start = new Date().getTime();

    function foo() { return 0; }

    function bar () { foo(); }

    for (var i = 0; i < calls; i++) {
        bar();
    }

    console.log('Unnested took %s ticks', new Date().getTime() - start);
}

function nested () {
    var start = new Date().getTime();

    function bar () {
        function foo() { return 0; }
        foo();
    }

    for (var i = 0; i < calls; i++) {
        bar();
    }

    console.log('Nested took %s ticks', new Date().getTime() - start);
}

function nestedReturning () {
    var start = new Date().getTime();

    var bar = (function () {
        function foo() { return 0; }

        return function () { foo(); };

    })();

    for (var i = 0; i < calls; i++) {
        bar();
    }

    console.log('Nested returning took %s ticks', new Date().getTime() - start);
}

notNested();

nested();

nestedReturning();

(Please keep in mind that this is in no way intended to be a proper performance test, but merely a sanity check)

Results:

Running this with nodejs yields the following result:

➝  node nested-functions.js 
Unnested took 1606 ticks
Nested took 2316 ticks
Nested returning took 1614 ticks

Here we can see, in this case we can see that nesting a function causes code to run about 1.4x as slow, while ensuring that the outer function is only created once by returning it is as performant as not nesting.

Somewhat of a difference there, but what about the different browsers?

In order to make testing these easier and thanks to Charlie Robbin’s advice (see comments), I went to jsperf.com and created a performance test

For people better with visualizing numbers:

(shows operations per second e.g., higher is better)

If you use a browser that’s not listed yet, head on over to see how your browser is doing.

As this data shows, there is a considerable impact when “carelessly” nesting functions.

How considerable depends on the browser (e.g., Firefox and IE seem to punish us the most). Chrome  handles them best and suffers only about 30% ,

Returning the outer function as an object and thus ensuring it only gets created once , pretty much fixes the performance hit in all browsers.

Conclusions:

  • nest functions, but do so wisely (e.g., as outlined in the ‘nestedReturning’ example)
  • be aware however that this pattern will increase the memory footprint of your application since the returned function closes over the inner one and thus prevents it from being garbage collected
  • if you are looking for the lowest footprint, highest performance option and can live with slightly less nicely structured code, declare functions at outer scope as much as possible

Note: make sure to use the revision 3 of above performance tests, as the initial ones were faulty and tested how lazy browsers evaluate functions instead of what they were supposed to.

Advertisements

8 Comments

%d bloggers like this: