I am currently using $q service from angular to make API calls like this:
var deferred = $q.defer();
$http.get(config.apiHost + details.url)
.success(function (data) {
deferred.resolve(data);
}).error(function (msg) {
deferred.reject(msg);
});
return deferred.promise;
but we can also use this approach also without using $q:
return $http.get(config.apiHost + details.url)
.success(function (data) {
return data;
}).error(function (msg) {
return msg;
});
and as $http itself returns the promise, I can also use more simplified approach:
$http.get(config.apiHost + 'posts')
.success(function (data) {
console.log(data)
}).error(function (msg) {
console.log(msg);
});
So what is the difference between all these specially between $q and $http, as both returns promise and both are async ? Does angular provides some additional functionality with $q ? I am not able to find any good answer.
$q is an angular defined service. It's the same as new Promise(). But $q takes things to the next level by enhancing additional feature that developers can use to perform complex tasks more simply. resolve(value) – resolves the derived promise with the value.
$q is integrated with the $rootScope. Scope Scope model observation mechanism in AngularJS, which means faster propagation of resolution or rejection into your models and avoiding unnecessary browser repaints, which would result in flickering UI. Q has many more features than $q, but that comes at a cost of bytes.
Promises in Angular provide an easy way to execute asynchronous functions that use callbacks, while emitting and completing (resolving or rejecting) one value at a time. When using an Angular Promise, you are enabled to emit a single event from the API.
Simply put you can use $q. defer() to create a Promise. A Promise is a function that returns a single value or error in the future. So whenever you have some asynchronous process that should return a value or an error, you can use $q. defer() to create a new Promise.
Promises in AngularJS are provided by the built-in $q service. They provide a way to execute asynchronous functions in series by registering them with a promise object. {info} Promises have made their way into native JavaScript as part of the ES6 specification.
$http
uses $q
, the first example is redundant, and so is the second. You just need to return the promise that $http.get
returns:
return $http.get(config.apiHost + details.url);
The above is the same as your first piece of code.
In addition, return msg
is not the same as deferred.reject(msg)
. The equivalent would be throw msg
or return $q.reject(msg)
Another thing to note is that success
and error
are non-standard, you want to use then
and catch
.
$q
is mainly only used for compatibility with libraries that don't support promises by default and when you can't rely on a native implementation of Promise
(for example - in older browsers like IE9). There's no reason (for you) to use it otherwise. An example would if you wanted to make a promise-based $timeout
. $http
itself uses $q
under the hood for these exact reasons.
Unlike what other (since deleted) answers have suggested, you do not need to use $q
in order to "store" the result of the $http
promise. I would not recommend storing the promise at all (as this tends to lead to spaghetti code), but if you must absolutely do this, you can just store the resultant promise from $http
; promises only ever execute once.
Any functions passed to then
after a promise has resolved/rejected will be resolved on the next tick, without re-invoking the original action that created the promise in the first place - IOW, the result of the promise is memoized within that object.
Also note that promises chain, which is abit out of scope for this answer, but it essentially means that the following pieces of code are equivalent
function legacyGet() {
const deferred = $q.defer()
$http.get('http://www.google.com')
.then((response) => deferred.resolve(Object.assign(response, {foo: bar}))
.catch((error) => deferred.reject(error))
return deferred.defer
}
function modernGet() {
return $http.get('http://www.google.com')
.then((response) => Object.assign(response, {foo: bar}))
}
To summarise: Your title is wrong. We don't prefer using $q, we only use it sparingly. Prefer to use an ES6 Promise unless you need to support browsers that don't have it and you can't use a polyfill.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With