Coffeescript与callback和简化的error handling

我想能够重构这个咖啡代码的error handling:

# 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) 

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

使用早期返回而不是条件分支,这样你保持你的代码简单明了,避免不必要的样板代码。

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

我是Caolanasynchronous库的忠实粉丝。 上述库的主要思想是每个callback的第一个参数是一个错误,如果没有错误,则调用链中的下一个函数。 所以你可能看起来像这样:

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

函数链会抛出第一个错误,这样你的最终callback实际上只负责处理一个错误。 这对于要停止并报告遇到的第一个问题的串行进程非常有用。