I would like to know if there is a way to hold requests in order to execute them one by one instead of all together?
Request 1
Request 2
Request 3
If i receive them almost together the idea is to execute Request 1 and after this request is complete then execute the others.
Dont forget i would like to do it using injectors.
Thanks in advance!!
You can hold requests using AngularJS Interceptors, by returning a promise in request method:
authInterceptor.$inject = ['$q', '$rootScope'];
function authInterceptor($q, $rootScope) {
return {
request: function(config) {
var deferred = $q.defer();
if(condition) {
deferred.resolve(config)
}
return deferred.promise;
}
};
}
In this example the requests will hold until meeting some condition.
What you can do is to keep a handle to every request (the deferred variable in above example), and send them by resolving each one in your desired order.
Related
Angularjs app here.
There are 2 controllers that do similar things.
In particular, they have an interval. Each 10 seconds they go to their own service.
These 2 different services also do similar things. Most important is that they go to an URL that looks like this:
example.com/fromTimestamp=2019-11-21T15:13:51.618Z
As the two controllers start more or less at the same time, in the example above they could generate something like:
controller/service 1: example.com/fromTimestamp=2019-11-21T15:13:51.618Z
controller/service 2: example.com/fromTimestamp=2019-11-21T15:13:52.898Z
This is because the parameter is created in the service with his line:
var timestamp = fromTimestamp ? '&fromTimestamp=' +fromTimestamp.toISOString() : '';
So maybe there will be a difference of some seconds. Or even only a difference of milliseconds.
I would like to make only one request, and share the data fetched from http between the two services.
The most natural approach would seem to be using cache.
What I could understand is that this call could make the trick:
return $http.get('example.com/fromTimestamp=2019-11-21T15:13:51.618Z', {cache: true});
But looking in the dev tools it is still making 2 requests to the server. I guess this is because they have 2 different urls?
If that is the problem, what could be another approach to this problem?
In my apps, when face with this problem, I use the $q provider and a promise object to suspend all calls to the same endpoint while a singleton promise is unresolved.
So, if the app makes two calls very close together, the second call will not be attempted until the promise created by the first call is resolved. Further, I check the parameters of the calls, and if they are the same, then the original promise object is returned for both requests. In your case, your parameters are always different because of the time stamp. In that case, you could compare the difference in time between the two calls, and if it is under a certain threshold in miliseconds, you can just return that first promise object. Something like this:
var promiseKeeper; //singleton variable in service
function(endpointName, dataAsJson) {
if (
angular.isDefined(promiseKeeper[endpointName].promise) &&
/*promiseKeeper[endpointName].dataAsJson == dataAsJson && */
lastRequestTime - currentRequestTime < 500
) {
return promiseKeeper[endpointName].promise;
} else {
deferred = $q.defer();
postRequest = $http.post(apiUrl, payload);
postRequest
.then(function(response) {
promiseKeeper[endpointName] = {};
if (params.special) {
deferred.resolve(response);
} else {
deferred.resolve(response.data.result);
}
})
.catch(function(errorResponse) {
promiseKeeper[endpointName] = {};
console.error("Error making API request");
deferred.reject(extractError(errorResponse));
});
promiseKeeper[endpointName].promise = deferred.promise;
promiseKeeper[endpointName].dataAsJson = dataAsJson;
return deferred.promise;
}
}
I have a very large angularjs app, that sells stuff and has filters
It seems that we need to support people on flaky connection.
That means that if user selects 'used product' filter and then he unselects 'used product', there will be a 2 calls to the server via $http.
$http.get("reloadresults?used=true", function (response) { $scope.items = response items; }); at 12:03:04 hours
$http.get("reloadresults?used=false", function (response) { $scope.items = response items; }); at 12:03:05
Now, image there is a bottleneck or something and the first call with 'used=true' returns last, then there is a problem with the filters.
I know there is a $http interceptor in angularjs, based on promises, how would i fix this problem? So that requests are processed in the order they are sent, meaning 'used=true' and only then used=false.
Edit: cant block thread, cant refactor, just need for the promises to fullfil in the order they were first sent. I think ill post answer later.
I din't understand your question well but i think you are looking for
$q.all(valid_request)
You could indeed ensure that success handlers are called in the correct order by forming a queue (a promise chain) however it is simpler, and better in this case, to nullify the previous request each time a new request is made.
There's a number of ways in which this could be achieved. Here's one ...
function cancelPrevious(fn) {
var reject_ = null;
return function(x) {
if(reject_) reject_(new Error('cancelled'));
return Promise.race(fn(x), new Promise(function(_, reject) {
reject_ = reject; // if reject_ is called before fn(x) settles, the returned promise will be rejected.
}));
};
}
which allows you to write ...
var get = cancelPrevious(function(str) {
return $http.get(str);
});
... and to make requests from any number of event threads :
get('reloadresults?used=true').then(function(response) {
// This function will be reached only if
// $http.get('reloadresults?used=true') fulfills
// before another get() call is made.
$scope.items = response.items;
});
...
// This call causes the then callback above to be suppressed if not already called
get('reloadresults?used=false').then(function(response) {
$scope.items = response.items;
});
Notes :
http requests are not canceled. Instead, the succuss path stemming from each request is made "cancelable" by racing against a rejectable promise.
side-effects included in the function passed to cancelPrevious() may be executed; in general, don't include such side effects.
I'm wanting to to have my app limit its requests to the server without saving the data. Is there a way I can do this without making a request to the server every time my http request is invoked? What are some of the different methods this can be done and best practices/trade offs for each?
That would depend on you needs. One approach would be to store the results in a request in a factory and retrieve those.
app.factory('DataService', function($http) {
var values;
var requestValues = function() {
$http.get("/api/getValues").then(
function(results){
values = results;
});
};
var getValues = function() {
return values;
};
return {
requestValues : requestValues, // this will make a http request and store the result
getValues: getValues // this will call the stored result (without making a http request)
}
});
And then in you controller call the functions to make a request for the values and then get the values. There are two functions, requestValues() to make the http request and save the result and getValues() to get the stored values without making a http request. Once requestValues() has been called, you should be able to call getValues() from anywhere to get the values without making a new http request.
myApp.controller('MyController', function ($scope, DataService) {
var init = function (){
DataService.requestValues(); // this will make the http request and store the result
$scope.items = DataService.getValues(); // this will get the result
};
var justGetValues = function(){
$scope.items = DataService.getValues(); // this will get the result (without making a http request)
};
});
Now you simply have to call DataService.getUpdates(); whenever you need the values. (You might want to wrap these in a promise. I have refrained from doing this due to simplicity)
Alternatively you could use the cache option as mentioned by #JLRishe. Angular's $http has a cache built in, so simply set cache to true in its options
$http.get(url, { cache: true})
.success(){
// on success
}.error(){
// on error
};
You can use the cache option in the config argument to the various $http methods:
$http.get('/someUrl', {
cache: true
});
The most obvious way is simply to have a JavaScript integer variable that counts how many requests have been made to the server, and when a defined maximum limit is reached, to stop making requests to the server.
Without knowing more about why you want to do it, it is difficult to be more specific.
I have the following OrientDB function:
http://localhost:2480/function/Application/getPassFailCount/9:600
And it returns the following JSON result:
{"result":[{"#type":"d","#version":0,"pass":16.0,"fail":2.0,"#fieldTypes":"pass=d,fail=d"}]}
What I need to do is to get the values of "pass" and "fail" to use in my web page.
So far I have done this with AngularJS:
$http.get('http://localhost:2480/function/Application/getPassFailCount/9:600').
success(function(data) {
$scope.data = data.result;
// $scope.passCount = ;
// $scope.failCount = ;
});
Currently it gives the error "401 Unauthorized". How do I authenticate the request?
And if possible, can anyone give some tips on how to get the passCount and failCount from the JSON result returned?
The OrientDB HTTP API documentation states that you have to use HTTP Basic authentication for issuing commands. That means you have to include an Authorization header along with your request.
There are a few ways to achieve this, here is a simpler one. Use the configuration object parameter for $http.get to set the header on the request:
function base64(str) {
return btoa(unescape(encodeURIComponent(str)));
}
$http.get('http://...', {
headers: { 'Authorization': 'Basic ' + base64(user + ':' + password) }
}).success(...);
You should definitely move all your database logic to an Angular service, so you can keep this code in one place instead of polluting your controllers.
To make it even cleaner, you could look into $http interceptors and write a request interceptor that adds the header to every HTTP call.
Regarding the JSON question: you can see that the result object contains an array with a single element. Use indexing to get the actual record.
var result = data.result[0];
$scope.passCount = result.pass;
$scope.failCount = result.fail;
If you wrote a service as I mentioned, you could hide this implementation detail from your controller.
function getCount() {
return $http.get(...).then(function (data) {
var result = data.result[0];
// the caller will only see this simpler object
return { pass: result.pass, fail: result.fail };
});
}
I'm facing this strange issue with the $http service: every request made to the API provided on the company that I work, wrapped in a $q.all(), return the same response.
var promises = [
$httpPromiseA(),
$httpPromiseB(),
$httpPromiseC()
];
$q.all(promises)
.then(function (response) {
$log.log(response);
});
// $log.log returns [expectedObjectFromA, expectedObjectFromA, expectedObjectFromA]
This occurs randomly: the expectedObjectFromA can be expectedObjectFromB or expectedObjectFromC. The fact is that all of the three objects return the same, or two of one and one of other, etc.
If I chain one after other, in a linear manner, they all work perfectly, but takes more time to acomplish the task, of course.
var def = $q.deferred();
var resolvedData = [];
$httpPromiseA()
.then(function (response) {
$log.log(response);
resolvedData.push(reponse);
return $httpPromiseB();
})
.then(function (response) {
$log.log(response);
resolvedData.push(reponse);
return $httpPromiseC();
})
.then(function (response) {
$log.log(response);
resolvedData.push(reponse);
return def.resolve(resolvedData);
});
return def.promise();
// $log.log returns [expectedObjectFromA],
// [expectedObjectFromB] and [expectedObjectFromC]
// as expected. ResolvedData brings [expectedObjectFromA,
// expectedObjectFromB, expectedObjectFromC].
Can you give me some directions on what may be happening here?
I'm using the core implementations of $http and $q. I've tried one $q.allSettled, applied as $decorator, based on the API resource of Kris Kowalk's Q, but didn't succeed too.
Thanks.
EDIT 1:
I cannot pass the arguments to the functions separately because it's a wrapper function thats call the $http service, here in my app. The wrapper function expects a String as the first argument, and an Object as the second. The wrapper function returns the $http calls.
EDIT 2:
This Plunker calls 2 concurrent requests, one to the Instagram API and the other to the Flickr API. The problem don't occur is this Plunker. I really don't know how to deal with this trouble. This is REALLY annoying.
In $q.all you'll want to pass in an array of promises, instead executing the function. $httpPromiseA.$promise instead of $httpPromiseA() and so on.
The problem was on the server side, which was having problems with simultaneous requests, answering all made together with the same response.
Thanks for all support and attention.