6

In the plain javaScript world I've learned that nested functions can be problematic because the inner function is "re-created" every time the outer function is called:

function outer(a) {
    function inner(arg1,arg2){
        return arg1 + arg2;
    }
    return inner(a, 6);
}
myVar = outer(4);

Apparently the inner function is garbage collected and the constant re-creation of it has a cost on performance. This could be re-factored as:

function inner(arg1, arg2) {
    return arg1 + arg2;
}

function outer(a) {
    return inner(a, 6);
}

myVar = outer(4);

If I am correct it seems that the tradeoff lies in the changing scope of inner; the fact that function inner no longer has access to outer's own variables. If I am correct so far, lets move to Node.JS. Node is heavy on callbacks, and my question is, are asynchronous callback functions typical in Node also "re-created" every time they are fired? Take the following common Node construct:

http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');
}).listen(1337, '127.0.0.1');

In reality the function can get pretty large; it can encompass a lot of functionality. Is the above callback "re-created" every time a client GETs or POSTs the server? If so, would it be better to always de-couple the callbacks as in the plain javaScript example:

function handleGET(req, res) {
   res.writeHead(200, {'Content-Type': 'text/plain'});
   res.end('Hello World\n');
}

http.createServer(handleGET).listen(1337, '127.0.0.1');

as a related bonus question, are event functions re-created too? Would they benefit from prior declaration?

myObj.on('someEvent', function someFunction() {...});

vs.

function someFunction() {...}
myObj.on('someEvent', someFunction);
4
http.createServer(function (req, res)
{
    // do stuff
});

is almost exactly the same as

function handler (req, res)
{
    // do stuff
}

http.createServer(handler);

The arguments passed to a called function are evaluated in the same scope as the call. Now, if you had done something like:

http.createServer(function (req, res)
{ 
  function handler (req, res)
  {
    // do stuff
  }
  return handler(req, res);
});

Then yes, you'd be creating a new function for every request, and that would be inefficient. In terms of something like a web server this is usually not a problem since the request handlers are often declared in a single place.

The only time you really want to nest functions (which is quite different from passing a function as an argument, as you are doing in your examples), is when you need references to the enclosing scope's variables (ie: a closure)

In answer to your second question, no. There's nothing different about event handler functions, and both your examples are functionally equivalent, and should essentially compile to the same machine code.

  • So if I understand you correctly, a function that is passed as an argument is not 'created' at the time that the calling statement is executed, but rather that function object is created when the scope containing the calling statement comes into focus, as if it had been defined separately as in my event example ? – Dave Aug 11 '14 at 14:47
  • Almost. My answer was more about the scope that the function is evaluated in, not necessarily the point at which it gets evaluated. A function declaration (eg: function foo() {}) will get hoisted to the top of the containing scope, whereas a function expression (eg: var foo = function() {} or function(){} as an argument) will get created at the point it is evaluated (like any other statement). – rossipedia Aug 12 '14 at 6:18
8

Node.JS doesn't fundamentally change the way Javascript works, and the issue you're describing is a Javascript issue.

More specifically, because the inner function is inside the scope of an outer function, it is recreated every time the inner function enters and leaves the outer scope. It's exactly the same thing that happens when you declare a variable inside of a function, as opposed to outside of it. Node.JS has nothing to say about all that.

Fundamentally, callback functions are just functions; they have no special property that changes the way they behave in local scope.

Related
JSlint error 'Don't make functions within a loop.'

1

Note that a modern JavaScript implementation will only create individual function objects for different instances of the same function, these objects can easily share the code.

Both of your first two examples should, at least in V8, have the inner function inlined by the optimizer, thus effectively removing the overhead of having a second function at all. I'll try to make time for some benchmarks, but for now I note that the first example could potentially be faster because it can be verified by simple static analysis that the inner function will never change. The second example has to be able to deal with the possibility that the global variable inner changes value.

You give the example code:

http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');
}).listen(1337, '127.0.0.1');

Note that this is not an example of multiple instances of the same function, createServer is called once and is in this process given the only instance of the anonymous function that is ever created. It is likely to call the anonymous function multiple times, but that is a different matter.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.