我使用这段代码是为了将经典的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…(时,不会调用then
或fail
函数。如何自动传播
我试图用它取代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
应用第二个回调,但也没有成功。
但是,当抛出不是我抛出的异常(SyntaxError、TypeError…(时,不会调用then或fail函数。
Q
只捕获从.then()
回调中抛出的异常。您需要自己明确地处理所有其他异常。
如何自动传播?
如果异常是从您自己的代码中抛出的,您可能会考虑在较低级别上使用Promises,并仅将您自己的编码放在then
回调中。
如果异常是从您调用的"classic nodejs function"中抛出的,您将需要catch
它。然而,可能有充分的理由来抛出异常(这是不可恢复的(,而不仅仅是用错误参数调用回调,这将是异步节点函数的"正常"设计方法。
如果您想在toPromise
方法中包含这样的功能,则需要包装函数调用:
try {
$this.apply(self, args);
} catch(e) {
deferred.resolve(e);
}
(function(…, callback) { … }).toPromise(this);
这是个坏主意。您不应该在自己的函数上使用toPromise
,而应该只使用那些提供给您的函数,并且具有非promise接口。请参阅教程部分中的开始如何想出一个真正返回Promise的函数。不要使用callback
变量。你很容易就会犯错误。特别是如果你有一个已经产生承诺的函数,你所需要做的就是把其他任务串在它后面
在您的具体情况下,它只是
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
实际上是有意义的。