Мы используем библиотеку обещаний Q в нашем API узла, но разрешаем вызов функций через обратные вызовы.
Например:
function foo(cb) {
Q.fcall(function () {
return true;
}).then(function (result) {
return cb(null, result);
}).catch(function (err) {
return cb(err, null);
});
}
Когда я запускаю свои модульные тесты мокко, если есть исключение в обратном вызове, это приводит к тому, что обратный вызов вызывается дважды.
Например:
var called = 0;
foo(function (err, res) {
called++;
console.log('err: ' + err);
console.log('res: ' + res);
console.log('called: ' + called);
throw Error(throw Error from foo!');
});
Это дает следующий результат:
err: null res: true называется: 1 err: Error: throw Error from foo! res: null вызвано: 2
Один из подходов, который мы нашли, заключался в следующем:
function foo2(cb) {
var _result, _err;
Q.fcall(function () {
return true;
}).then(function (result) {
_result = result;
}).catch(function (err) {
_err = err;
}).finally(function () {
_.defer(cb, _err, _result);
});
}
Идея заключалась в том, чтобы иметь одно место, где будет вызываться обратный вызов, и попытаться предотвратить ошибки разработчика, принудительно применяя функцию defer для очистки стека вызовов.
При таком подходе наш обратный вызов вызывается один раз, и любые ошибки (или, в нашем случае, утверждения) обрабатываются непосредственно вызывающим.
Есть ли лучший метод, который мы можем использовать? Мне кажется, что это довольно распространенный сценарий, поэтому я полагаю, что существует более чистое решение ...
err: null res: true called: 1 err: Error: throw Error from foo! res: null called: 2
‹- поймал один раз. Как вы думаете, почему он называется дважды? Обратный вызов БЫЛ вызывался дважды, но это то, что вы хотели, не так ли? - person Amit   schedule 31.08.2015