I\'m using the RSVP library distributed inside Ember.js and I\'m trying to figure out the correct pattern for reporting fatal errors inside a promise -- particularly I want
New answer --
In this video panel discussion with ember core developers, at one point the developers all share one debugging tip:
http://www.youtube.com/watch?v=L9OOMygo1HI
Tom Dale specifically addresses the issue of swallowed exceptions inside promises and recommends use of the new Ember.RSVP.onerror feature for debugging errors inside promises which would have otherwise gone unreported because no rejection handler was attached.
I think that is the correct answer to my question -- although I don't yet know how to use the RSVP.onerror callback (or in which ember releases its available) ...
Nice question!
You could get away with the setTimeout
within a dev environment. But for production where you log these errors for reporting for instance, You will want to avoid setTimeout
as it's non-deterministic. You could end up seeing errors that aren't really accurate, but occurred due to some order in which the setTimeout
fired.
You can do this by moving your checks to the first then
of the promise, and then returning that thenable
instead of deferred directly.
I prefer to use Ember.Deferred
instead of Ember.RSVP.Promise
. Deferred
is a layer over RSVP
that has a nicer API. It avoids needing to nest the whole thing inside a callback to Ember.RSVP.Promise
. Ember.Deferred
provides resolve
and reject
as methods.
model: function(params) {
var promise = Ember.Deferred.create();
var successCallback = function(resp) {
promise.resolve(resp);
};
var errorCallback = function(err) {
promise.reject(err);
};
var thenable = promise.then(function(resp) {
if (resp.isError) {
throw new Error(resp.errorMessage);
} else {
return resp;
}
});
// some api that takes a callback
this.callApi(params, successCallback, errorCallback);
return thenable;
},
Throwing an error at any point in the promise/API will automatically reject the promise. So you don't need to catch and rethrow anything.
This allows for 3 different types of responses.
successCallback with response data.
successCallback({data: 'foo'});
successCallback with error in response.
successCallback({isError: true, errorMessage: 'Response data is wrong'});
errorCallback with message.
errorCallback('Incorrect use of API');
See this jsbin to try this out.
You could clean this up a bit if the API that you call uses promises instead of callbacks. Then you can just chain the thens
.