当 运行 mocha 单元测试时,如何避免我的 Q promise catch 块在 NodeJS 回调样式 API 中被调用两次?

How can I avoid my Q promise catch block being called twice in a NodeJS callback-style API when running mocha unit tests?

我们在节点 API 中使用 Q promise 库,但允许通过回调调用函数。

例如:

function foo(cb) {
 Q.fcall(function () {
    return true;
 }).then(function (result) {
    return cb(null, result);
 }).catch(function (err) {
    return cb(err, null);
 });
}

当我 运行 我的 mocha 单元测试时,如果回调 中存在异常 ,则会导致回调被调用两次。

例如:

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 called: 1 err: Error: throw Error from foo! res: null called: 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);
  });
}

我们的想法是在一个地方调用回调,并通过强制延迟清除调用堆栈来尝试防止开发人员错误。

使用这种方法,我们的回调被调用一次,任何错误(或者在我们的例子中,断言)都由调用者直接处理。

我们可以使用更好的技术吗?我觉得这是一个很常见的场景,所以我想有一个更干净的解决方案...

修改您的 foo 函数以使用 2 个单独的处理程序在同一个 then 调用中处理履行和拒绝:

function foo(cb) {
 Q.fcall(function () {
    return true;
 }).then(function (result) {
    return cb(null, result);
 }, function (err) {
    return cb(err, null);
 });
}