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
Related
Promises let the program run asynchronously and save time because it retrieves information from both URL at the same time.
Since the promises run asynchronously, for $q.all(promises) function, is it true that resultList[0] always has information from 1.json and resultList[1] has information from 2.json? The promises.push() might not have data from 1.json first right? Since the promise run asynchronously, it might only have the data from 2.json first before 1.json.
After running the page (using Promises) in other server, it gives error "Origin 'www.dns' not allowed by Access-Control-Allow-Origin." and "XMLHttpRequest cannot load 'a.json' due to access control checks", for Jquery GET method can use JSONP to solve the error. But is there a way that can solve in promises?
var promises = [];
var loadingJson = function(url){
var defer = $q.defer();
$http.get(url).then(function(results){
defer.resolve(results);
}, function(err){
defer.reject(err);
});
return defer.promise;
};
promises.push(loadingJson('example.com/1.json'));
promises.push(loadingJson('example.com/2.json'));
$q.all(promises).then(function(resultList){
// Your hanadling here, resultList contains the results of both API calls.
}, function(errList){
// Your error handling here.
});
Short answer: YES.
From the documentation of $q.all (emphasis mine):
Returns a single promise that will be resolved with an array/hash of
values, each value corresponding to the promise at the same index/key
in the promises array/hash. If any of the promises is resolved with a
rejection, this resulting promise will be rejected with the same
rejection value.
In short, the result of $q.all will maintain the order of the original list, regardless of the order in which each promise individually resolves.
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;
});
};
});
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/
If I want to promisify all code paths in myFunction, do I need to create a deferred inside myFunction?
function myFunction(options) {
if(!options) {
throw 'foo'; // But I want the API for myFunction to be promise-based...
}
return promiseBasedApi.doSomethingAndReturnPromise();
}
do I need to create a deferred inside myFunction?
(That's jQuery terminology, the general case would be "Do I need to create a promise in my function?")
Only if your function doesn't already have a promise it can return; frequently, it does, if it's waiting on any asynchronous operation (ajax, some other promise-based API, etc.) to complete.
if(!options) {
throw 'foo'; // But I want the API for myFunction to be promise-based...
}
If you're asking if you need to create an reject a promise for the error that options is not provided, no, I wouldn't expect that of an API. There are two aspects to an asynchronous operation's API:
Initiation
Completion
In the above, failing to supply options is an error during the initiation of the request. I would expect an inline exception, not an asynchronous error callback.
Errors processing the request (HTTP failures, etc.) would be errors I'd expect via the promise's rejection mechanism.
No, you do not need a deferred or the Promise constructor in your function. You do need those only for non-promise-based APIs. Even then, you should not use it globally, but a separate promise capability for each asynchronous code path.
In your case, you should just return a rejected promise instead of throwing:
function myFunction(options) {
if (!options) {
return Promise.reject(new FooError()); // as promised!
}
return promiseBasedApi.doSomethingAndReturnPromise();
}
An alternative, if you are using Bluebird, would be to wrap your throwing-or-(promise)-returning function in Promise.method. See also Should an async API ever throw synchronously? and Should a Promise.reject message be wrapped in Error? for related discussions.
I have a controller that needs to retrieve two separate REST resources that will populate two dropdowns. I would like to avoid populating either of them until both $http.get() calls have returned, so that the dropdowns appear to be populated at the same time, instead of trickling in one after the other.
Is it possible to bundle $http.get() calls and elegantly set the $scope variables for both returned arrays, without having to write state logic for both scenarios, e.g. a returns before b, b returns before a?
The return value of calling the Angular $http function is a Promise object using $q (a promise/deferred implementation inspired by Kris Kowal's Q).
Take a look at the $q.all(promises) method documentation:
Combines multiple promises into a single promise that is resolved when
all of the input promises are resolved.
Parameters
promises – {Array.<Promise>} – An array of promises.
Returns
{Promise} – Returns a single promise that will be resolved with an array of values, each value corresponding to the promise at the same index in the promises array. If any of the promises is resolved with a rejection, this resulting promise will be resolved with the same rejection.
You can use $q.all to "join" the results of your http calls, with code similar to:
app.controller("AppCtrl", function ($scope, $http, $q) {
$q.all([
$http.get('/someUrl1'),
$http.get('/someUrl2')
]).then(function(results) {
/* your logic here */
});
}
do you mean something like this:
function someController( $scope, $http, $q ) {
var first_meth = $http.get("first_url"),
second_meth = $http.get("second_url");
$q.all([first_meth, second_meth]).then(function(all_your_results_array) {
//here you'll get results for both the calls
});
}
Ref: Angular JS Doc
You could use the Async javsscript library here: https://github.com/caolan/async.
Use the series call. It will make the 2 calls and then call one callback when both are done.