A promise ate my homework (or exception) Published on Jun 10, 2013

If you’ve ever used a library based on promises such as Ember.js/Ember Data you’ve probably stumbled upon this. Or maybe you haven’t, but the app was silently failing with no error message, which is even worse.

The reason for this is simple and it is actually an intentional feature. If any error happens inside the promise, it will be treated as rejection.

var promise1 = new Ember . RSVP . Promise ( function () { throw "bazinga" ; // this gets "swallowed", unless we handle it }); promise1 . isRejected ; // => true promise1 . then ( null , function ( error ) { console . log ( error ); // prints out "bazinga" });

But this isn’t all what if we throw an exception inside resolve / reject ?

// *`RSVP.resolve` returns a resolved promise* Ember . RSVP . resolve (). then ( function () { throw "bazinga" ; // swallowed again });

One might think that adding a rejection handler would solve this so let’s try

Ember . RSVP . resolve (). then ( function () { throw "bazinga" ; }, function ( error ) { console . log ( error ); });

This is where the real frustration hits. At first sight you would expect the second callback to be called with the error, but that’s not true, the promise can’t reject after it was fulfilled. Fortunately there’s a simple solution here as well. If a promise errors inside any of the handlers it returns another rejected promise, which means we can handle the error with a second .then call

var promise = Ember . RSVP . resolve (). then ( function () { throw "bazinga" ; }); promise . isRejected ; // => true promise . then ( null , function ( error ) { console . log ( error ); });

If everything goes well and there is no error thrown .then will return a fulfilled promise.

var promise = Ember . RSVP . resolve (). then (); promise . isFulfilled ; // => true

While this all might seem confusing at first the good thing about promises is that they are super consistent. You just need to learn a few core concepts and you’ll be rarely surprised.

Written by Jakub Arnold of sensible.io