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/
Related
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;
});
};
});
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 am making an ajax call to server to fetch some data.
$.ajax(
{
url: "myserver",
method: "GET",
}.success(function(data)
{ }
.error(function(e)
{ }
)
I have been reading about .then().
Is there any performance benefit of using .then() over .success()?
Is there any particular scenario where I should use .then() and .success()?
Plus, whoever answers,please brief me in short What is Promises.
You should be using then as the success and error have been deprecated.
https://docs.angularjs.org/api/ng/service/$http
The $http legacy promise methods success and error have been
deprecated. Use the standard then method instead. If
$httpProvider.useLegacyPromiseExtensions is set to false then these
methods will throw $http/legacy error.
.then( ) call returns a promise while .success( ) is more traditional way of registering callbacks and it doesn't return a promise.
Moreover .then() is commonly used where you need to chain promises whereas .success() method is a streamlined, convenience method when you don't need to chain call nor work with the promise API.
I would recommend using .then() and .catch(). Those methods are in line with the CommonJS standard. As you use other Promise libraries, it's more likely that they'll use those two methods.
I would also avoid using the .then(successCallback, failureCallback) approach, as it is not standard and less obvious.
This is a great article which helps you to understand Promise
http://andyshora.com/promises-angularjs-explained-as-cartoon.html
and
The major difference between the 2 is that .then() call returns a promise (resolved with a value returned from a callback) while .success() is more traditional way of registering callbacks and doesn't return a promise.
I personally prefer .then(), here is a very good blog on why .success() is not preferred.
For an API call I would do something like this:
$http.get('www.domain.com/someAPI').then(function (results) {
// On successful promise
doSomethingHere();
}, function (error) {
// On failed promise
handleError();
});
.Success and .then both work same but there are lot of difference between there response unit, In angular and ajax success work same after evening thing goes completed and you might need to fetch response data then User .success,
In .then it happens before .Success and After .Success.
so if You have Loading bar in your html code use before success .then for loading...
and after success use .then for hiding it.
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/