最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Coffeescript with callbacks & simplified error handling - Stack Overflow

programmeradmin1浏览0评论

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 Promiseplete (/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)

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.plete (/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)
Share Improve this question edited Jan 8, 2012 at 9:22 mkopala asked Jan 8, 2012 at 9:09 mkopalamkopala 1,3223 gold badges12 silver badges15 bronze badges 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). – tokland Commented Jan 8, 2012 at 13:29
  • I think you meant, runit Case.findOne, { caseId: data.id }, 'Vote failed', (mycase) -> – Gautham Badhrinathan Commented Aug 18, 2012 at 20:24
Add a ment  | 

3 Answers 3

Reset to default 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 piles 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);
  }]));
};

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!'

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.

发布评论

评论列表(0)

  1. 暂无评论