4

I would like to be able to refactor the error handling from this coffeescript code:

# Do some stuff with 2 levels of asynchronous callbacks and error handling
vote = (res, data) ->
  Case.findOne { caseId: data.id }, (err, mycase) ->
    if err
      console.error 'Vote failed'
    else
      myvote = new Vote
        case: mycase._id
      myvote.save (err) ->
        if err
          console.error 'Could not add vote'
        else
          console.log 'Success!'

to something like this:

# Run my function, do error handling, and run the callback if no error
runit = (func, arg, errmsg, callback) ->
  func arg, (err, docs) ->
    if err
      console.log errmsg + ': ' + err
    else
      callback docs

# Original code, simplified
vote = (res, data) ->
  runit Case.findOne { caseId: data.id }, 'Vote failed', (mycase) ->        
      myvote = new Vote
        case: mycase._id
      runit myvote.save, 'Could not add vote', () ->   
          console.log 'Success!'

Obviously, the runit function needs be able to handle one or more arguments correctly, which I didn't attempt to code correctly.

If I run it like this, I get an error:

node.js:201
    throw e; // process.nextTick error, or 'error' event on first tick
          ^
TypeError: Cannot read property 'findOne' of undefined
    at /tmp/node_modules/mongoose/node_modules/hooks/hooks.js:27:28
    at /tmp/lib/api.js:227:12
    at Promise.<anonymous> (/tmp/lib/api.js:216:16)
    at Promise.<anonymous> (/tmp/node_modules/mongoose/lib/promise.js:120:8)
    at Promise.<anonymous> (events.js:67:17)
    at Promise.emit (/tmp/node_modules/mongoose/lib/promise.js:59:38)
    at Promise.complete (/tmp/node_modules/mongoose/lib/promise.js:70:20)
    at /tmp/node_modules/mongoose/lib/query.js:885:15
    at model.<anonymous> (/tmp/node_modules/mongoose/lib/document.js:181:5)
    at model.init (/tmp/node_modules/mongoose/lib/model.js:181:36)
2
  • the eternal boilerplate problem of error-handling in node.js. A search in SO will give you some ideas about the issue (if they satisfy you is another matter). Commented Jan 8, 2012 at 13:29
  • I think you meant, runit Case.findOne, { caseId: data.id }, 'Vote failed', (mycase) -> Commented Aug 18, 2012 at 20:24

3 Answers 3

3
# Run my function, do error handling, and run the callback if no error
runit = (func, args..., errmsg, callback) ->
  func args..., (err, docs) ->
    if err
      return console.log errmsg + ': ' + err
    callback docs

# Original code, simplified
vote = (res, data) ->
  runit Case.findOne { caseId: data.id }, 'Vote failed', (mycase) ->        
    myvote = new Vote
      case: mycase._id
    runit myvote.save, 'Could not add vote', ->   
      console.log 'Success!'

What runit compiles to:

runit = function() {
  var args, callback, errmsg, func, _i;
  func = arguments[0], args = 4 <= arguments.length ? __slice.call(arguments, 1, _i = arguments.length - 2) : (_i = 1, []), errmsg = arguments[_i++], callback = arguments[_i++];
  return func.apply(null, __slice.call(args).concat([function(err, docs) {
    if (err) return console.log(errmsg + ': ' + err);
    return callback(docs);
  }]));
};
Sign up to request clarification or add additional context in comments.

Comments

2

Use early returns instead of conditional branches, that way you keep your code simple and sane, and avoid unnecessary boilerplate code.

vote = (res, data) ->
  Case.findOne { caseId: data.id }, (err, mycase) ->
    return console.error 'Vote failed' if err?
    myvote = new Vote
      case: mycase._id
    myvote.save (err) ->
      return console.error 'Could not add vote' if err?
      console.log 'Success!'

Comments

1

I'm a huge fan of Caolan's async library. The big idea with said library is that the first argument of every callback is an error, and if no error is present, the next function in the chain is called. So your could could look like this:

vote = (res, data) ->
  async.series [
    (next) -> Case.findOne { caseId: data.id }, next
    (next) -> myvote = new Vote({case: mycase_id}).save(next)
  ], (err, result) ->
    if err
      console.error err
    else
      console.log "Success!"

The chain of functions breaks on the first error thrown, that way your final callback is really only responsible for handling a single error. This is great for serial processes where you want to halt and report the first issue you run into.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.