带有回调和简化错误处理的 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) ->
【参考方案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 等到从回调中设置标志,然后继续代码的下一部分