Working with Angular Promises you might want to avoid the Deferred antipattern, which involves the creation of a second deferred object to manage resolve and rejection events.

At the same time, you will probably experiment another common mistake:

The above code actually is catching the error so that the promise will be always fullfilled. Any catch chained to the method catchError  will never be run. And this is fine as long as you handled properly the exception and produced the right result, otherwise will just leave you with a black hole eating all you errors.

In order to allow the exception to bubble you may find pretty straightforward to explicitly throw an error:

Actually this one doesn’t work given that any exception in an asynchronous block is being swallowed by the framework.

So… what’s the solution? $q provides us with the methods $q.reject()  and $q.resolve() . Is the first one that we need to return in order to pass the error down to the next chain’s node.

Even if it looks weird at the first sight, it makes totally sense:

  • in the first case, we caught the error so there isn’t anything more to catch
  • in the second we threw an exception inside an asyncronous block, which is being swallowed as per specifications
  • in the last example we returned a new rejection, yet to be managed

I have to point out that in my opinion you should catch the exception only in one place, when you know you can manage it: doesn’t make sense to catch it, handle it and the recreate it again to be passed down unless it is used in order to send a message, emit an event or just log the error without handling it.

Another use case for such a behaviour is when you handle an error which can have several outcomes and only in the corner cases you generate a new one with a more specific description and data. In the following example you can see how the method first tries to recover from an error and then, if is a fatal one, reject the promise with a specific description:

I prepared a small example of this behaviour on github: just clone it and run as follows

You will find four methods doing the following things:

  1. a pass-through method, just returning the raw promise
  2. a catcher method, which is returning the promise and catching the failure
  3. a method that tries to propagate the failure using a normal JS exception
  4. a method that uses the $q.reject()  to return a new failure

Have fun!