Node.js соглашение для возврата нескольких ошибок через обратный вызов?

Итак, общее соглашение для функций обратного вызова в Node.js должно "зарезервировать" первый параметр для ошибки (если таковая существует). Например:

callSomeBlockingFcn( function callbackWhenDone(err, result) {
  if( err ) ...
});

Если вам нужно вернуть более одной ошибки - скажем, например, несколько ошибок проверки данных - считается ли она плохой формой для передачи массива объектов ошибок? Пример:

var callSomeBlockingFcn = function(callback) {
  // multiple errors to report back...
  callback( [ err1, err2, ...] );
}

Или предпочтительнее избегать массивов и возвращать один объект со свойством, ссылающимся на массив (если необходимо)? Пример:

var callSomeBlockingFcn = function(callback) {
  // multiple errors to report back...
  callback( { errors: [ err1, err2, ...] } );
}

Ответ 1

спустя 3 года:

Любой, кто помещает массив в обратный вызов, сойдет с ума.

Правильное решение - вернуть error в качестве первого аргумента. Если вы хотите возвратить несколько ошибок, вероятно, вы используете ошибки для не исключительных случаев.

В этом случае он должен идти в слове "значение" обратного вызова, то есть во втором аргументе. Первый аргумент - для одной неожиданной оперативной ошибки.

Если у вас несколько неожиданных операционных ошибок (маловероятно), вы можете сделать что-то вроде этого MultiError

Оригинал

Я думаю, что нет ничего плохого в возвращении массива ошибок.

Хотя вы можете вернуть новый пользовательский ValidationError, у которого есть свойство "messages", которое является массивом.

а)

function validateX(x, cb) {
  ...
  if (errorMessages) {
    return cb(errorMessages);
  }
}

б)

function ValidationError(msgs) {
  this.messages = msgs;
}

function validateX(x, cb) {
  ...
  if (errorMessages) {
    return cb(new ValidationError(errorMessages));
  }
}

Ответ 2

Нашел этот вопрос, выполнив поиск по той же проблеме. Хотя я огляделся и пришел к выводу, что я не считаю, что err должен быть чем-то вроде ошибки или null.

Лучший "авторитетный" источник, который я нашел, это тема справки Nodejitsu:

http://docs.nodejitsu.com/articles/errors/what-are-the-error-conventions

В node.js считается стандартной практикой обрабатывать ошибки в асинхронных функциях, возвращая их в качестве первого аргумента для текущего обратного вызова функции. Если есть ошибка, первый параметр передается объекту Error со всеми подробностями. В противном случае первый параметр имеет значение null.

Но я думаю, что вы можете сделать аргумент из интуиции о том, почему это так. Хотя в коде есть много тестов if (err), чтобы решить, что-то было или не было ошибкой, вы не должны передавать 0 или false или undefined или NaN или пустую строку. Вы должны быть в состоянии проверить с помощью if (err == null), если хотите.

Передача чего-то в поле err, которое не является нулевым, но не соответствует if (err instanceof Error), кажется хитроумным. Поэтому я предлагаю не использовать массивы или объекты. Если вы это сделали, обратите внимание также, что ни одна из ошибок в вашем массиве не будет определять местоположение, где была создана общая ошибка. Это то место, где произошла "настоящая ошибка", потому что именно момент принятия решения заключался в том, что ошибки, которые он дал, не могли справиться с этим.

Однако это означает, что вам потребуется немного больше работы, чтобы получить это:

function MultipleError (errs) {
    // http://stackoverflow.com/a/13294728/211160

    if (!(this instanceof MultipleError)) {
        return new MultipleError(errs);
    }

    Error.call(this);
    this.errs = errs;

    // captureStackTrace is V8-only (so Node, Chrome)
    // https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi

    Error.captureStackTrace(this, MultipleError);
};

MultipleError.prototype.__proto__ = Error.prototype;
MultipleError.prototype.name = 'MultipleError';
MultipleError.prototype.toString = function () {
   return 'MultipleError: [\n\t' + this.errs.join(',\n\t') + '\n]';
}

Немного перебор, возможно. Но если вы действительно не можете выбрать ошибку для представления агрегации и подумать, что кто-то может быть заинтересован в наборе ошибок вместо одного, казалось бы (?), Что то, что вы хотите сделать... позволяет вызывающий, чтобы проверить массив errs, если они хотят.