带有回调和简化错误处理的 Coffeescript

Posted

技术标签:

【中文标题】带有回调和简化错误处理的 Coffeescript【英文标题】:Coffeescript with callbacks & simplified error handling 【发布时间】:2012-02-05 06:47:15 【问题描述】:

我希望能够从此咖啡脚本代码重构错误处理:

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

到这样的事情:

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

显然,runit 函数需要能够正确处理一个或多个参数,我没有尝试正确编码。

如果我这样运行它,我会得到一个错误:

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)

【问题讨论】:

node.js 中错误处理的永恒样板问题。在 SO 中搜索会给你一些关于这个问题的想法(如果他们让你满意是另一回事)。 我想你的意思是,runit Case.findOne, caseId: data.id , 'Vote failed', (mycase) -&gt; 【参考方案1】:
# 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!'

runit 编译为:

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);
  ]));
;

【讨论】:

【参考方案2】:

使用早期返回而不是条件分支,这样您的代码就可以保持简单和理智,并避免不必要的样板代码。

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

【讨论】:

【参考方案3】:

我是Caolan's async library 的忠实粉丝。所述库的大想法是每个回调的第一个参数都是错误,如果不存在错误,则调用链中的下一个函数。所以你的可能看起来像这样:

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

函数链在抛出第一个错误时中断,这样您的最终回调实际上只负责处理单个错误。这对于您想要停止并报告遇到的第一个问题的串行进程非常有用。

【讨论】:

以上是关于带有回调和简化错误处理的 Coffeescript的主要内容,如果未能解决你的问题,请参考以下文章

如何在 CoffeeScript 胖箭头回调中引用实际的“this”?

Coffeescript 等到从回调中设置标志,然后继续代码的下一部分

我使用咖啡脚本的 ajax 帖子未处理成功回调

如何优雅地处理使用带有闭包的 NSURLSessionTask 的方法中的错误?

带有 Iframe 事件和更改处理的 ReactJs

presentShareDialogWithParams 发布到 FB 墙上,但回调处理程序结果显示错误