3

I am currently working on a node.js web service which utilizes Express.js and Mongoose. Recently, I figured I would try my hand at CoffeeScript, as I have heard that there are some benefits to be had. However, I have noticed something a little unsettling, and I was curious if someone could clarify.

Here is one of my routes in plain javascript:

router.post('/get/:id', decorators.isManager, function(req, res) {
    Group.findById(req.params.id, function(err, grp) {
            if(err) res.status(500).end();
            if(grp == null) res.status(500).send('The group could not be found');
            res.send(grp);
    });
});

However, with the following (nearly equivalent coffeescript):

router.post '/get/:id', decorators.isManager, (req, res) ->
  Group.findById req.params.id, (err, grp) ->
    res.status(500).end() if err
    res.status(500).send 'The group could not be found' if not grp?
    res.send grp

Re-compiling this to javascript returns the following:

router.post('/get/:id', decorators.isManager, function(req, res) {
    return Group.findById(req.params.id, function(err, grp) {
            if(err) res.status(500).end();
            if(grp == null) res.status(500).send('The group could not be found');
            return res.send(grp);
    });
});

Will those extra returns effect the performance of my application, does it alter the way it works? I tested it, it seems to be the same response time however I am not sure the impact this will have on multiple nested queries. Thank you!

Guilherme Rodrigues
  • 2,818
  • 1
  • 17
  • 22

1 Answers1

4

Nice question! This has been largely discussed in this pull request.

Regarding performance

Bear in mind that returning undefined or any other value is almost equivalent, performance-wise.

However, all differences are quite small, so this shouldn't get you worried. You can compare the actual speed variations in this quick-and-dirty benchmark: http://jsperf.com/return-undefined-vs-value

There is one special case when it might hurt a little more: when the last statement in your function would result in an array. CoffeeScript will allocate the array and return it for you.

For example in CoffeeScript you might write:

state = 1

changeState = ->
  (state++ for i in [0..9])

Which will be transpiled to:

var changeState, state;

state = 1;

changeState = function() {
  var i, j, results;
  results = [];
  for (i = j = 0; j <= 9; i = ++j) {
    results.push(state++);
  }
  return results;
};

But you don't even want the results, you just wanted to add to state!

In this case, the best option is to add a empty return statement:

state = 1

changeState = ->
  (state++ for i in [0..9])
  return

Which will result in

var changeState, state;

state = 1;

changeState = function() {
  var i, j;
  for (i = j = 0; j <= 9; i = ++j) {
    state++;
  }
};

Regarding unintended consequences

CoffeeScript will never change the behaviour of your code - unless you are expecting a function to always return undefined.

This is not common, nor very useful, though. If you want to check the return value, there's probably something to be had. If you never used the return value, returning something won't matter.

As a long time CoffeeScript user, my opinion is that you'll enjoy implicit return sooner rather than later. It nudges you to write in a more functional manner.

Guilherme Rodrigues
  • 2,818
  • 1
  • 17
  • 22