Using `$q.defer()` in AngularJS? Try the $q 'constructor' instead.
Although I'm a great fan of using the
($q
) Promise API
in AngularJS, I never really liked using $q.defer()
and its
Deferred API. I
always found using var deferred = $q.defer()
together with $.resolve(..)
and
$.reject(..)
to be too verbose.
After recently checking the $q service documentation I stumbled upon the $q
constructor that
results in way less verbose code. To illustrate the usage of the $q
constructor I will create a function that wraps the result of a
Geolocation#getCurrentPosition
invocation as an AngularJS $q
promise. Using the traditional $q.defer()
approach the function wrapper will look like this.
/* @return {Promise} */ function getGeoLocation() {
var deferred = $q.defer();
$window.navigator.geolocation.getCurrentPosition(
function (position) {
// success callback
return deferred.resolve(position);
},
function (positionError) {
// error callback
return deferred.reject(positionError);
},
);
return deferred.promise;
}
When using the $q
constructor, I could rewrite the code as follows, resulting
in less verbose code:
/* @return {Promise} */
function getGeoLocation() {
return $q(function (resolve, reject) {
$window.navigator.geolocation.getCurrentPosition(
function (position) {
// success callback
resolve(position);
},
function (positionError) {
// error callback
reject(positionError);
},
);
});
}
And since in this case we are merely passing through the arguments of the success and error callbacks, I could rewrite the code to be even smaller:
/* @return {Promise} */ function getGeoLocation() {
return $q(function (resolve, reject) {
$window.navigator.geolocation.getCurrentPosition(resolve, reject);
});
}
As you can see, using the
$q constructor produces code with less boilerplate, making it more readable in the process. Notice that although it’s being called the “$q
constructor” we are not actually doing a new
on $q
. Possibly, the AngularJS
team calls it this way because it mimics the ECMAScript 2015
Promise
constructor API. Next to the $q
constructor there are some other alternatives
to using the verbose $q.defer()
. In most cases you can probably use a less
verbose alternative as is nicely described in
this
blog post that I stumbled upon while doing some additional research for my own
blog post.