Coffeescript с обратными вызовами и упрощенной обработкой ошибок - PullRequest
4 голосов
/ 08 января 2012

Я хотел бы иметь возможность рефакторинга обработки ошибок из этого кода coffeescript:

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

Ответы [ 3 ]

3 голосов
/ 08 января 2012
# 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 голосов
/ 09 января 2012

Используйте ранние возвраты вместо условных переходов, чтобы ваш код был простым и разумным, а также избегал ненужного стандартного кода.

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!'
1 голос
/ 11 июня 2012

Я большой поклонник Асинхронной библиотеки Каолана .Основная идея этой библиотеки заключается в том, что первый аргумент каждого обратного вызова является ошибкой, и, если ошибки нет, вызывается следующая функция в цепочке.Таким образом, вы могли бы выглядеть так:

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

Цепочка функций разрывается при первой выданной ошибке, таким образом, ваш окончательный обратный вызов действительно отвечает только за обработку одной ошибки.Это отлично подходит для последовательных процессов, где вы хотите остановить и сообщить о первой проблеме, с которой вы столкнулись.

...