【问题标题】:Q promises propagate errors and exceptionsQ 承诺传播错误和异常
【发布时间】:2014-05-01 14:57:45
【问题描述】:

我正在使用此代码将经典的 nodejs 函数转换为 Promise 函数:

  Object.defineProperty(Function.prototype, "toPromise", {
    enumerable: false,
    configurable: false,
    writable: false,
    value: function(self) {
      var $this;
      $this = this;
      return function() {
        var arg, args, deferred, _i, _len;
        deferred = Q.defer();
        args = [];
        for (_i = 0, _len = arguments.length; _i < _len; _i++) {
          arg = arguments[_i];
          args.push(arg);
        }
        args.push(function() {
          args = Array.prototype.slice.call(arguments);
          if (args[0] instanceof Error) {
            return deferred.reject.apply($this, args);
          } else {
            return deferred.resolve.apply($this, args);
          }
        });
        $this.apply(self, args);
        return deferred.promise;
      };
    }
  });

我在一个函数上调用它来获取另一个函数。像这样:

  exports.list = (function(userid, options, callback) {
    // do something 
    // success ->
        callback(data);
    // error ->
        callback(err)
  }).toPromise(this);

但是当一个不是我抛出的异常(SyntaxError、TypeError...)被抛出时,thenfail 函数不会被调用。如何自动传播?

我试图用它替换 toPromise 但这没有用(即使它与我的函数一起使用)

  Object.defineProperty(Function.prototype, "toPromise", {
    enumerable: false,
    configurable: false,
    writable: false,
    value: function(self) {
      var $this;
      $this = this;
      return Q.denodeify(this.bind(Kitty));
    }
  });

我还尝试对then 应用第二个回调,但我也没有工作。

【问题讨论】:

  • WTH 确实 canThis 返回了一个承诺(您在其上调用 .then())但被放置在您手动 toPromise() 的函数表达式中呢?
  • 什么是error.throwError()?你无法捕捉到的错误抛出在哪里?
  • 如果canThis 确实接受了回调,那么您的意思是, function(can) 而不是).then(function(can)
  • @Bergi 不,我犯了一个错误:这是一个承诺
  • 那么你在用这个callback.toPromise() 做什么?

标签: javascript node.js error-handling q


【解决方案1】:

但是当一个不是我抛出的异常(SyntaxError、TypeError...)被抛出时,则不会调用 then 或 fail 函数。

Q 只捕获从.then() 回调中抛出的异常。您需要自己明确处理所有其他异常。

如何自动传播?

如果异常是从您自己的代码中抛出的,您可以考虑在较低级别上使用 Promises,并将您自己的代码仅放在 then 回调中。

如果异常是从您调用的“经典 nodejs 函数”中抛出的,则需要 catch 它。但是,抛出异常(这是相当不可恢复的)而不是仅使用错误参数调用回调可能有充分的理由,这将是异步节点函数的“正常”设计方法。

如果您想在 toPromise 方法中包含此类功能,则需要包装函数调用:

try {
  $this.apply(self, args);
} catch(e) {
  deferred.resolve(e);
}

(function(…, callback) { … }).toPromise(this);

这是个坏主意。你不应该在你自己的函数上使用toPromise,而只能使用那些给你的并且具有非承诺接口的函数。请参阅教程部分中的The Beginning 如何设计一个真正返回 Promise 的函数。不要使用callback 变量。太容易一些错误逃脱了你。尤其是如果你有一个已经产生了 Promise 的函数,你需要做的就是在它之后链接其他任务。

在你的具体情况下,它只是

exports.list = function(userid, options) {
  return canThis(userid, "mod", "browse").then(function(can) {
    if (can === false)
      throw error.throwError("Forbidden", "UNAUTHORIZED");
    if (options.perPage > 50) {
      throw error.throwError("Too much mods per page", "INVALID_PARAMS");

    var Mod = mongoose.model("Mod");
    return Q.all([ // I would assume that listing and counting can happen in parallel?
      Q.ninvoke(Mod, "list", options),
      Q.ninvoke(Mod.count(), "exec")
    ]).spread(function(mods, count) {
      mods.totalCount = count;
      return mods;
    }, function(err) { // and throw this error when one happens in either?
      throw error.throwError(err, "DATABASE_ERROR");
      // not sure whether you need errors.handleResult at all
      // (not with a callback, at least)
    });
  });
};

现在所有returns 都说得通了。

【讨论】:

  • 非常感谢。在一个小的测试脚本中,我得到了没有你的代码打印的错误。但是,添加行时输出不同。我很快就会在我的应用中尝试。
  • 为什么我不能在我自己的函数中使用它?它更简单!
  • 不幸的是,它没有用;当我运行一个未定义的函数时,页面加载并加载并且没有任何反应,即使我在 resolve(e) 之前添加了一个 console.log
  • 不,这并不简单——而且你想使用 Promise!
  • 运行未定义的函数”是什么意思?更具体的代码示例会很好。
猜你喜欢
  • 2018-10-22
  • 2015-05-12
  • 2014-01-04
  • 2015-12-23
  • 1970-01-01
  • 1970-01-01
  • 2016-12-05
  • 2012-12-14
  • 2015-10-09
相关资源
最近更新 更多