All about $q and Promises in Angular

August 15, 2016 0 Comments angular, $q, promises

All about $q and Promises in Angular

You've seen $q, maybe used it but haven't uncovered some of the awesome features $q provides such as $q.all() and $q.race(). This article dives into ES2015 Promise API and how it maps across to $q for AngularJS. This post is all about $q, enjoy!

Table of contents

What is a Promise?

A promise is a special type of Object that we can either use, or construct ourselves to handle asynchronous tasks. We deem them promises because we are "promised" a result at a future point in time. For example an HTTP call could complete in 200ms or 400ms, a promise will execute when resolved.

A promise has three states, pending, resolved or rejected. Using $q in Angular, we can construct our own promises, however let's look at the ES2015 Promise Object first to get familiar on how to create one.

ES2015 Promises

The main things here are Promise and the resolve and reject arguments:

We simply call new Promise() and inside can perform an asynchronous task, which may be for wrapping particular DOM events, or even wrapping third-party libraries that are not promise Objects.

For example, wrapping a pseudo third-party library called myCallbackLib() which gives us a success and error callback, we can construct a Promise around this to resolve and reject where appropriate:

$q constructor

The $q implementation in AngularJS is now available in the same aspect as the native ES2015 Promise Object, therefore we can do this:

The only difference here from above is changing new Promise() to $q(), simple enough.

Ideally you'd implement this inside a service:

Which would then be injected into a component controller:

Or used as a bindings property on a routed component and mapped with a routing resolve:

When to use $q

At the moment we've only looked at some pseudo-examples, here's my implementation on wrapping the XMLHttpRequest Object to become a promise-based solution, this kind of thing should be the only real reason(s) you create your own $q promises:

Please note, this is not advocating the use and creation of the XMLHttpRequest, use $http inside Angular, which creates and returns a promise Object for you:

Which means, you do not, and shouldn't ever do this as it's just creating a new promise Object from an existing promise Object:

Golden rule: use $q for non-promise stuff, that's it! Well, only create your Promises in this case, however you can use other methods such as $q.all() and $q.race() alongside other promises.

$q.defer()

Using $q.defer() is just another flavour, and the original implementation, of $q() as a Promise constructor. Let's assume the following code, adapted from the before example using a service:

$q.when() / $q.resolve()

Use $q.when() or $q.resolve() (they are identical, $q.resolve() is an alias for $q.when() to align with ES2015 Promise naming conventions) when you want to immediately resolve a promise from a non-promise Object, for example:

Note: $q.when() is also the same as $q.resolve().

$q.reject()

Using $q.reject() will immediately reject a promise, this comes in handy for things such as HTTP Interceptors at the point of no return to return, so we can just return a rejected promise Object:

$q.all()

The time will likely arise where you need to resolve multiple promises at once, this is easily achieved through $q.all() by passing in either an Array or Object of promises which will call .then() once both are resolved:

$q.race()

The $q.race method is one of the newer arrivals to Angular, and is similar to $q.all(), however whichever promise resolves first is the only response Object passed back to you. Assume API call 1 and API call 2 are both executed simultaneously, and API call 2 resolves before API 1, you'll only get API call 2 as the response Object. In other words the fastest promise wins and is returned on its own:

Conclusion

Use $q for constructing promises from non-promise Objects/callbacks, and utilise $q.all() and $q.race() to work with existing promises.

If you like this article, check out my advanced Angular 1.5 master course which covers all the $q, $httpProvider.interceptors, ui-router, component architecture and the new .component() API.

For anything else, the $q documentation.

All about $q and Promises in Angular


Tag cloud