I have following code in which i am trying to execute httpt request serially
Following is code
var httpPostData = function (postparameters,postData){
return $http ({
method : 'POST',
url : URL,
params : postparameters,
headers: headers,
data : postData
}).success (function (responseData){
return responseData.data;
})
}
for (var app of appArray){
var addAppPromise = httpPostData (restartAppParams,app);
addAppPromise.then(function(status){
console.log(status.data);
})
}
appArray is list of servers where i am connecting one by one and doing some stuff as per parameter i am passing (restartAppParams) by above http post.
I want this execution to happen serially i.e. next http request should be executed only if previous one is finished and response has received.
Any idea how to do that..
You can use Array.prototype.reduce to achieve this:
.controller('Samplecontroller', function($http, $q) {
var restartAppParams = {};
var httpPostData = function(postparameters, postData){
return $http ({
method : 'POST',
url : URL,
params : postparameters,
headers: headers,
data : postData
});
};
appArray.reduce(function(promise, app) {
return promise.finally(function() {
return httpPostData(restartAppParams, app)
.then(function(response) {
console.log(response.data);
});
})
}, $q.when());
});
Try this:
var httpPostData = function(postparameters, postData, next) {
return $http ({
method : 'POST',
url : URL,
params : postparameters,
headers : headers,
data : postData
}).success (function (responseData) {
if (typeof next == 'function') {
next();
}
});
}
var appArrayCopy = appArray.slice();
function fetch() {
if (appArrayCopy.length) {
var app = appArrayCopy.shift();
httpPostData(restartAppParams, app, fetch);
} else {
// finished
}
}
angularjs uses asynchronous ajax calls by default. It's actually hardcoded and can't be changed (see line 77 in this commit, which is HEAD of master branch at the time, I'm writing this).
Also, keep in mind that synchronous calls block everything else which is basically against the non-blocking approach javascript was built for.
If your app is dependant on the requests beeing done one after another, you could chain them using the promise and a recursive call.
Something like this should work:
function runXhr(app) {
var addAppPromise = httpPostData (restartAppParams,app);
addAppPromise.then(function(status){
console.log(status.data);
// calls the next service if appArray has any services left
var app = appArray.shift();
if (app) {
runXhr(appArray.shift());
}
else {
return;
}
});
}
Related
I am iterating over an array and for each object in the array I need to make an api call. And then in the .done of the said call I need to update the object that was used to make the call as well as know when all calls have finished successfully.
applicants.forEach((applicant, index) => {
var defer = $.Deferred();
GetAppOverview(applicant.id).done((status) => {
applicant.status = status;
});
});
My ajax service looks like this.
module.exports = function(Id) {
var defer = $.Deferred();
$.ajax({
url : url+'/'+id
method : 'GET',
headers : {
'Content-Type' : 'application/json'
},
success : function( data) {
defer.resolve(data);
},
error : function( error ) {
defer.reject(error);
},
});
return defer.promise();
};
MVC application (ASP.NET MVC, client: jquery).
Problem: The second ajax-request wait, when the first ajax request will done.
I need, when the first and the second ajax-requests executes immediatly in one time.
The page sends to server to determine the count of records (the first ajax-request), very long (~5-7 seconds).
The operator click the buttom to open the card to edit it (the second ajax-request, fast, get the Dto-model).
The user doesn't need to wait the first request, he wants to work immediatly.
As a result, in Chrome in network page, two requests in status 'pending'. The second waits the first.
Question, how can I send requests, to execute asynchronously ?
The first ajax-request:
`window.jQuery`.ajax({
type: 'POST',
url: Url.Action("GetCountBooks", "Book");
contentType: "application/json; charset=utf-8",
dataType: 'json',
data: JSON.stringify({ typeBook: "...", filter: "..." };),
success: function (data) {
// show in UI page the count of books by filter and params
},
error: function (data) {
//show error
}});
public class BookController : Controller
{
[HttpPost]
public NJsonResult GetCountBooks(string typeBook, Filter filter)
{
var data = DbProvider.GetCountBooks(typeBook, filter)
if (data.Result == ResultType.Success)
{
var count = data.Data;
return new NJsonResult
{
Data = new { Data = count }
};
}
return new NJsonResult
{
Data = new { Error = "Error while counting the books." }
};
}
}
The second ajax-request:
`window.jQuery`.ajax({
type: 'POST',
dataType: 'json',
contentType: "application/json",
url: Url.Action("GetBookById", "Book"),
data: JSON.stringify({ id: bookId }),
success: function (data) {
// show jquery dialog form to edit dto-model.
},
error: function (data) {
//show error
}});
public class BookController : Controller
{
[HttpPost]
public NJsonResult GetBookById(int id)
{
var data = DbProvider.GetBookById(id)
if (data.Result == ResultType.Success)
{
var book = data.Data;
return new NJsonResult
{
Data = new { Data = book }
};
return new NJsonResult
{
Data = new { Error = "The book is not found." }
};
}
return new NJsonResult
{
Data = new { Error = "Error while getting the book." }
};
}
}
I Cannot union ajax requests into one! The user can send various second request.
You need a fork-join splitter to fork 2 tasks and join based on some condition.
For example here is my implementation:
function fork(promises) {
return {
join: (callback) => {
let numOfTasks = promises.length;
let forkId = Math.ceil(Math.random() * 1000);
fork_join_map[forkId] = {
expected: numOfTasks,
current: 0
};
promises.forEach((p) => {
p.then((data) => {
fork_join_map[forkId].current++;
if (fork_join_map[forkId].expected === fork_join_map[forkId].current) {
if (callback) callback(data)
}
})
});
}
}}
Pass any number of async tasks (promises) into fork method and join when all are done. The done criteria here is managed by simple global object fork_join_map which tracks the results of your fork-join process (global is not good but its just an example). The particular fork-join is identified by forkId which is 0..1000 in this example which is not quite good again, but I hope you got the idea.
With jQuery you can create promise with $.when( $.ajax(..your ajax call) )
In the end you can join your promises like this
fork([
$.when( $.ajax(..your ajax call 1) ),
$.when( $.ajax(..your ajax call 2) )
]).join(() => {
// do your logic here when both calls are done
});
It's my own implementation, there may be already-written library functions for this in jQuery - I dont know. Hope this will give you a right direction at least.
The solution is to add attribute to Asp Controller: [SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
http://johnculviner.com/asp-net-concurrent-ajax-requests-and-session-state-blocking/
I'm currently using a factory called http that when I invoke it, I make a web request. this receives as a parameter the url of the web request.
app.factory('http', function ($http) {
var oHttp = {}
oHttp.getData= function (url) {
var config={
method: 'GET',
url: url
}
return $http(config).then(function(data) {
oHttp.data=data.data;
},function(response) {
alert("problem, can you trying later please?")
});
}
return oHttp;
});
function HelloCtrl($scope, http) {
http.getData('https://www.reddit.com/.json1').then(function(){
if(http.data!=undefined){
console.log(http.data)
}
})
}
I would like the promise not to be executed on the controller if the result of the web request is not satisfied or there is a problem. is there any better solution? I want to avoid doing this every time I make a web request, or do not know if it is the best way (see the if):
//I am putting "1" to the end of the url to generate an error.
http.getData('https://www.reddit.com/.json1').then(function(){
//validate that the result of the request != undefined
if(http.data!=undefined){
alert(http.data.kind)
}
})
In my real project I make n web requests using my factory http, I do not want to do this validation always. I do not know if I always have to do it or there is another solution.
this is my code:
https://plnkr.co/edit/8ZqsgcUIzLAaI9Vd2awR?p=preview
In rejection handlers it is important to re-throw the error response. Otherwise the rejected promise is converted to a successful promise:
app.factory('http', function ($http) {
var oHttp= {};
oHttp.getData= function (url) {
var config={
method: 'GET',
url: url
}
return $http(config).then(function(response) {
̶o̶H̶t̶t̶p̶.̶d̶a̶t̶a̶=̶r̶e̶s̶p̶o̶n̶s̶e̶.̶d̶a̶t̶a̶;̶
return response.data;
},function(response) {
alert("problem, can you trying later please?")
//IMPORTANT re-throw error
throw response;
});
}
return oHttp;
});
In the controller:
http.getData('https://www.reddit.com/.json1')
.then(function(data){
console(data)
}).catch(response) {
console.log("ERROR: ", response.status);
});
For more information, see You're Missing the Point of Promises.
In Service
app.factory('http', function ($http) {
var oHttp = {}
oHttp.getData= function () {
return $http({
method: 'GET',
url: 'https://www.reddit.com/.json1'
});
}
return oHttp;
});
In controller
function HelloCtrl($scope, http) {
var httpPromise = http.getData();
httpPromise.then(function(response){
console.log(response);
});
httpPromise.error(function(){
})
}
So I tried this in codepen having ripped your code out of plinkr
https://codepen.io/PocketNinjaDesign/pen/oGOeYe
The code wouldn't work at all...But I changed the function HelloCtrl to a controller and it seemed happier....?
I also set response.data to default to an empty object as well. So that way if you're populating the data in the page it will be empty if nothing arrived. You can then in some instances on the site check the length if it's really required.
app.factory('http', function ($http) {
var oHttp = {}
oHttp.data = {};
oHttp.getData= function (url) {
var config = {
method: 'GET',
url: url
}
return $http(config).then(function(response) {
oHttp.data = response.data || {};
}, function(response) {
alert("problem, can you trying later please?")
});
}
return oHttp;
});
app.controller('HelloCtrl', function($scope, http) {
http.getData('https://www.reddit.com/.json').then(function(){
alert(http.data.kind);
})
});
I am trying to return an object from a $rootScope function called retrieveUser() in AngularJS. The object is returned. I have run console.log() on the response of the function ran when $http is successful. Here is my $rootScope function:
$rootScope.retrieveUser = function() {
var apiUrl = "http://104.251.218.29:8080";
if($cookies.get('tundraSessionString')) {
var cookie = $cookies.get('tundraSessionString');
$http({
method: "POST",
url: apiUrl + "/api/master/v1/auth/checkauth",
data: "sessionString=" + cookie,
headers: {
'Content-Type' : 'application/x-www-form-urlencoded;',
'Cache-Control': 'no-cache'
}
}).then(function mySuccess(response) {
if(response.data.event == "error") {
window.location = "/auth/logout";
} else {
return response.data;
}
})
} else {
window.location = "/auth/login";
}
};
With this method, I access it in my controller such as this (and console.log() just to test my work):
vm.user = $rootScope.retrieveUser();
console.log($rootScope.retrieveUser());
But, I have yet to get this to work. I have tried specifying specific objects in an array in my $rootScope function. I know it runs, because I have the $rootScope consoling something when it is run, and it shows a console.log() of the response of the $http request. It looks like this:
Object {event: "success", table: Object}
event:"success"
table:Object
__proto__:Object
Yet, when I console.log() the vm.user with the function $rootScope.retrieveUser(), even though the function is supposed to be returning the object, I simply receive "undefined".
I have been banging my head on this for days, read some articles on functions/objects and I still cannot figure this out. We're two days in.
try this:
if($cookies.get('tundraSessionString')) {
var cookie = $cookies.get('tundraSessionString');
//return a promise
return $http({
method: "POST",
url: apiUrl + "/api/master/v1/auth/checkauth",
data: "sessionString=" + cookie,
headers: {
'Content-Type' : 'application/x-www-form-urlencoded;',
'Cache-Control': 'no-cache'
}
}).then(function mySuccess(response) {
if(response.data.event == "error") {
window.location = "/auth/logout";
}
else {
return response.data;
}
})
}
else {
window.location = "/auth/login";
}
and
$rootScope.retrieveUser().then(function(user){vm.user = user;})
What you are returning from retrieveUser when your cookie is set is what $http returns, which is a promise. Try this:
$rootScope.retrieveUser().then(function(user){vm.user = user;})
retrieveUser fn doesn't return your data :)
$http is asynchronous function and you should read about promises
function handleUser(user){
//do something
}
function retrieveUser(callback){
$http({...}).then(function(response){
callback(response.data.user);
});
}
//how to use it:
retrieveUser(handleUser);
but first of all you may need a service for getting some data instead of using $rootScope
and secondly you can pass a user in your template in script tag
then you don't need another http request and user will be globaly available
<script>var user=<?php echo json_encode($user);?></script>
hey guys I know this issue posted a lot, but nothing doesn't help me that is why I asking this question.Question is I am facing an issue of sending a synchronous request to php.
here is my Model function which is sending request.
State.pushData = function () {
$http({
method: 'POST',
url: 'pushData.php?action=pushdata',
data: {'status': 'push', 'email' : State.campemail},
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function(response){
if(response.error){
console.log(response.error);
return;
}
State.getCartData();
State.selectedItems = [],
});
}
this pushData function send a post request to defined url. and fetch a response. the code written is suppose to execute "State.getCartData()" function on success of request sent initially. But this is not working in this way. both request executes at once.
I had tried $http with .post and then methods but same results. like this
State.pushData = function () {
$http.post('pushData.php?action=pushdata',
{'status': 'push', 'email' : State.campemail}
).then(function(response){
if(response.error){
console.log(response.error);
return;
}
State.getCartData();
State.selectedItems = [],
});
}
I want to send request asynchronously, that once pushQuote request completes after that getCartData() function will execute. please share your experience on this. thanks in advance.
got an answer to my question after some brainstorming. I return $http in my model and call .then() on returned response. it worked as I want to send request once first is completed successfully. Here is my model function
State.pushData = function () {
return $http.post('pushData.php?action=pushdata',
{'status': 'push', 'email' : State.campemail}
);
}
in above function I just send post request to server and return its response to controller function. which executes right after returning from model. here is my controller function.
scope.pushIt = function() {
var responseObj = State.pushData();
responseObj.then(
function() { //successs call back
/*Business logic*/
State.getCartData();
State.selectedItems = []
},
function() { //Error call back
/*Business logic*/
}
);
}
Beauty of this approach is you can use then method as many as you want. they will all execute one by one in chain.
scope.pushIt = function() {
var responseObj = State.pushData();
responseObj.then(
function() { //successs call back
/*Business logic*/
},
function() { //Error call back
/*Business logic*/
}
).then(
function() { //successs call back
/*Business logic*/
},
function() { //Error call back
/*Business logic*/
}
);
}