This question already has answers here:
AngularJS Promises, $q, defer
(2 answers)
Closed 5 years ago.
I am new to angularjs.I saw $q in restful api calls to check the promise.
$q.defer() was used to retain the promise object.
I read about the promises but I didn't get anything.
although I can make the api call without $q, however it is used somewhere in articles.
So I want to know the exact use of $q and difference in making api calls without $q.
Kindly help.
thanks
I think the article I wrote about $q might help you.
Introduction to $q
$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.
This is a sample for creating a promise using $q
angular.module("app",[])
.controller("ctrl",function($scope,$q){
var work = "resolve";
var promise = $q(function(resolve, reject) {
if (work === "resolve") {
resolve('response 1!');
} else {
reject('Oops... something went wrong');
}
});
promise.then(function(data) {
alert(data)
})
})
$q.defer()
$q.defer() return the instance of the promise constructor. Once you create a defer object there are following methods and properties that you can access from that object
resolve(value) – resolves the derived promise with the value. If the value is a rejection constructed via $q.reject, the promise will be rejected instead.
reject(reason) – rejects the derived promise with the reason. This is equivalent to resolving it with a rejection constructed via $q.reject.
notify(value) - provides updates on the status of the promise's execution. This may be called multiple times before the promise is either resolved or rejected.
promise – {Promise} – promise object associated with this deferred
See the example
angular.module("app",[])
.controller("ctrl",function($scope,$q){
var work = "resolve";
function getData(){
var obj = $q.defer();
if (work === "resolve") {
obj.resolve('response 1!');
} else {
obj.reject('Oops... something went wrong');
}
return obj.promise;
}
getData().then(function(data) {
alert(data)
})
})
$q.all()
If a user need to send multiple request one shot,then the user can use $q.all() service.
$q.all([$http.get('data1.json'),$http.get('data2.json')])
.then(function(response){
console.log(response[0].data) // data1.json response
console.log(response[1].data) // data1.json response
})
In here,there are two http request sent simultaneously to two separate JSON files to get data. The response comes as an array and response order is same as the HTTP request order.
$q.race()
$q.race() is very similar to $q.all(). But instead of sending response of each request, it will only return the one request response. Specifically, only return the response of first request that been executed. That does not mean it’s not going to send other requests. All the requests are sending but it's only return the response of the first request that executed.
$q.race([$http.get('data1.json'),$http.get('data2.json')])
.then(function(response){
console.log(response[0].data) // return one response
})
In here response can be either data1.Json or data2.json. That's the downfall of using this method. Since its return the response of the first executed request, can’t be sure which request response will resolved by the promise. This method useful for bulk requests which you don’t want to see the response of all the requests
Conclusion
Use $q for constructing promises from non-promise Objects/callbacks, and utilize $q.all() and $q.race() to work with existing promises.
I like this question. Because, I too faced this.
This is a service that helps you run functions asynchronously, and use their return values when they are done processing.
Brief Description
Refer example
Promise with $q
Example :
app.service("githubService", function($http, $q) {
var deferred = $q.defer();
this.getAccount = function() {
return $http.get('https://api.github.com/users/haroldrv')
.then(function(response) {
// promise is fulfilled
deferred.resolve(response.data);
// promise is returned
return deferred.promise;
}, function(response) {
// the following line rejects the promise
deferred.reject(response);
// promise is returned
return deferred.promise;
});
};
});
Related
This question already has answers here:
Why are AngularJS $http success/error methods deprecated? Removed from v1.6?
(2 answers)
Is this a "Deferred Antipattern"?
(3 answers)
Closed 4 years ago.
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.
$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.
In angular mostly all the services returns promises only, but there are some instances where you would like to create your own deferred object using $q.
Case 1
When you are using a library which does not support promise or you have created your own function and want to return a promise.
Case 2
When you are using any construct which by default returns a promise but you want to return a separate promise based on some on some condition.
Example: In angular $http returns a promise only but now if you want that if the response of this promise contains a particular value then only you want to return resolved else return failure then you need to create your own deffered object and need to resolve or fail it based on the value returned by $http response.
I don't know what is the exactly difference between AngularJS $q service and simply using .then() after async request.
Simple example with .then() :
function InboxService($http) {
this.getEmails = function getEmails() {
return $http.get('/emails');
};
}
And when using the service (just part of code):
InboxService.getEmails()
.then(function (response) {
// use response
});
What is the difference with $q service with resolve and reject ?
What is the difference with $q service with resolve and reject ?
I assume you are asking about the usage of var deferred = $q.defer() with subsequent deferred.resolve() or deferred.reject()? In this case, the answer is that you don't need it since you already have a promise object returned by $http service. In fact, manually constructing another new promise with $q is not recommended and considered an anti-pattern.
In cases where you work with asynchronous functions (timeouts, ajax-requests) that are not already wrapped into promise, then this is a case when you might want to use $q to create and return promise. But once again, in your case you don't need it as $http service constructs promise for you and one more is simply redundant.
The $q is superfluous and in most cases is not needed. http://www.codelord.net/2015/09/24/$q-dot-defer-youre-doing-it-wrong/
I want to get promise of asynchronous call without writing any service.
I have written some API to get data from back-end in JavaScript, but following code is not written in any service. I want to access the following promise in another JavaScript file. How can I access the promise in different file?
var cust_Promise = $q.defer() ;
var apt_data={some data};
$http.post(api,apt_data)
.success(function (response,status) {
cust_Promise.resolve('Success');
return cust_Promise.promise ;
}) ;
The $http service returns promises.
Simply save the returned promise.
var apt_data = {some data};
var promise = $http.post(url, apt_data);
This means the AngularJS framework supports passing them to other functions, returning them as the values from other functions, and assigning them to variables or storing them in data structures.
The fulfilled results or rejected error information can be retrieved by using the standard .then and .catch methods.
var derivedPromise = promise.then (function onfullFilled(response) {
$scope.data = results.data;
//return for chaining
return response;
}).catch ( function onRejected(response) {
console.log(response.statusText);
//throw to chain rejection
throw response;
});
Because calling the .then method of a promise returns a new derived promise, it is easily possible to create a chain of promises. It is possible to create chains of any length and since a promise can be resolved with another promise (which will defer its resolution further), it is possible to pause/defer resolution of the promises at any point in the chain. This makes it possible to implement powerful APIs.1
From the Docs:
The $http API is based on the deferred/promise APIs exposed by the $q service. While for simple usage patterns this doesn't matter much, for advanced usage it is important to familiarize yourself with these APIs and the guarantees they provide.
General usage:2
The $http service is a function which takes a single argument — a configuration object — that is used to generate an HTTP request and returns a promise.
The response object has these properties:
data – {string|Object} – The response body transformed with the transform functions.
status – {number} – HTTP status code of the response.
headers – {function([headerName])} – Header getter function.
config – {Object} – The configuration object that was used to generate the request.
statusText – {string} – HTTP status text of the response.
A response status code between 200 and 299 is considered a success status and will result in the success callback being called. Note that if the response is a redirect, XMLHttpRequest will transparently follow it, meaning that the error callback will not be called for such responses.
Additional Resources
Ninja Squad -- Traps, anti-patterns and tips about AngularJS promises
What is the explicit promise construction antipattern and how do I avoid it?
Angular execution order with $q
So this my controller:
app.controller('dbCtrl', function($scope, $http) {
$http.get("http://private-abc.apiary-mock.com/bus")
.success(function(response) {
$scope.network = response.networkupdates;});
});
What I wanted to do next is call a 2nd HTTP request, I guess in terms of best practice would it be best to create a 2nd controller to call the 2nd HTTP or would it be best to include the 2nd HTTP call in this current controller (and if so, how?)
Thanks.
So one of the cool aspects of using promises is that they can be chained. So in your case, you are calling:
$http.get("http://private-abc.apiary-mock.com/bus")
Which returns a promise that you can then chain to another promise like so:
var requests = $http.get("http://private-abc.apiary-mock.com/bus").then(function(response) {
$scope.network = response.networkupdates;
// make second get call and return it to chain the promises
return $http.get("some-other-endpoint").then(function(otherResponse) {
// you can do something here with the response data
return otherResponse;
});
});
What you have now is two chained promises that will return the final value, so if you call this later:
requests.then(function(otherResponse) {
// or you can do something here
doSomething(otherResponse);
});
As far as best practices for Angular, I would say you are better off creating a service or factory to handle any and all http requests. Controllers are really just meant to bind data to the view; services are where your business logic and data population should happen.
You can make your $http calls in the same controller.
The $http service is a function which takes a single argument — a configuration object — that is used to generate an HTTP request and returns a promise with two $http specific methods: success and error. It internally uses $q (a promise/deferred implementation inspired by Kris Kowal's Q).
If your two $http are independent of each other you use the $q.all to "join" the results of your http calls.
Example :
$q.all([
$http.get("http://private-abc.apiary-mock.com/bus"),
$http.get('/someUrl')
]).then(function(results) {
$scope.network = results[0];
$scope.whatevername= results[1]
});
}
If your http calls are dependent on one another then you can use the concept of chaining.
for example:
$http.get("http://private-abc.apiary-mock.com/bus").then(function(result) {
$scope.network = result.networkupdates;
return $http.get("someurl").then(function(res) {
return res;
});
});
For refernce of q you can see https://github.com/kriskowal/q
For refernce of $q service you can see https://docs.angularjs.org/api/ng/service/$q
Return an angular $resource from a factory after an asynchronous function call.
Below shows an example of an angular factory in which I'm attempting to return a $resource.
I'm trying to make an asynchronous function call using another service to receive the web service path before returning the $resource.
Is this possible?
angular.module('app').factory('newService', function($resource, configService) {
configService.get(function(config) {
return $resource(config.webServicePath + '/api/names', {},
{ 'update': { method:'PUT' } }
);
});
});
Would anybody have an example of either a service, provider, or factory returning a resource after an asynchronous function call to receive information like above.
It would also be helpful if you could provide an example of the newService being used in a controller.
Thanks in advance for the help.
currently, it's the callback that's returning the resource, which doesn't help you much. You can't delay a return statement until an async function has completed, but you can work with $q promise.
ngular.module('app').factory('newService', function($resource, configService, $q) {
var resourcePromise = $q.defer();
configService.get(function(config) {
resourcePromise.resolve($resource(config.webServicePath + '/api/names', {},
{ 'update': { method:'PUT' } }
));
});
return resourcePromise.promise;
});
Here's how $q works
You need to return a value that you get in the future, so you defer it using $q.defer()
This returns a deferred object.
You make your async call, and in its success callback, you call .resolve on the deferred object.
If the callback fails, you call .rejecton the deferred object.
You return deferredobject.promise, which is a promise object.
Using a service that returns promises
When you expect a value from a promise, you can listen for it by passing a callback to its thenmethod. If the promise might be rejected (the operation failed), it's a good idea to pass a second callback, which will be called when the promise is rejected.
Here's a simple example of a service that returns a promise, and how to use it:
http://jsfiddle.net/rP5Gh/