Q承诺传播错误和例外

我正在使用这个代码,以便将一个经典的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); 

但是,当我抛出的exception(SyntaxError,TypeError …)被抛出时,则不会调用thenfail函数。 如何自动传播它?

我试图通过replacetoPromise,但这并没有奏效(即使是在我的function)

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

我也试过应用第二个callback,但我没有工作。

但是,当我抛出的exception(SyntaxError,TypeError …)被抛出时,则不会调用then或fail函数。

Q只会捕获从.then()callback中引发的exception。 你需要明确地处理所有其他exception。

如何自动传播它?

如果exception是从你自己的代码中抛出的,你可以考虑在底层使用Promise,然后把你自己的代码放在callback函数里。

如果从调用的“经典nodejs函数”抛出exception,则需要catch该exception。 但是,为什么会抛出一个exception(这是相当不可恢复的),而不是仅仅使用error参数调用callback,这可能是很好的原因,这将是asynchronous节点函数的“常规”devise方法。

如果你想在toPromise方法中包含这样的function,那么需要包装函数调用:

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

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

这是一个坏主意。 你不应该在自己的function上使用toPromise ,而只能使用那些给予你的function,并且有非promise的接口。 请参阅教程中的开始部分,了解如何构build一个真正返回Promise的函数。 不要使用callbackvariables。 太容易一些错误逃脱你。 特别是如果你有一个已经产生承诺的函数,你需要做的就是在它之后连接其他的任务。

在你的具体情况下,这很简单

 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) }); }); }; 

现在所有的return都是有道理的。