But when an exception that wasn't thrown by me (SyntaxError, TypeError...) is thrown, the then or fail function isn't called.
Q
does only catch the exceptions that are thrown from a .then()
callback. You need to deal with all other exceptions yourself explicitly.
How to propagate it automatically?
If the exception is thrown from your own code, you might consider using Promises on a lower level, and put your own code in then
callbacks only.
If the exception is thrown from "classic nodejs function" that you call, you will need to catch
it. However, there might be good reasons why an exception is thrown (which is rather unrecoverable) in instead of just calling the callback with the error argument, which would be the "normal" design approach of an asynchronous node function.
If you would want to include such feature in your toPromise
method, it would require to wrap the function call:
try {
$this.apply(self, args);
} catch(e) {
deferred.resolve(e);
}
(function(…, callback) { … }).toPromise(this);
That's a bad idea. You should not use toPromise
on your own functions, but only those that are given to you and have the non-promise interface. See The Beginning in the Tutorial section how to come up with a function that returns a Promise genuinely. Do not use a callback
variable. Too easily some error escapes you. Especially if you have a function that already yields a promise, all you need to do is chain other task after it.
In your specific case, it's simply
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)
});
});
};
Now all those return
s actually make sense.