Wait for AJAX to finish before proceeding with the loop? - javascript

Why is it that whenever I put an ajax inside a for loop, it doesn't synchronize well?
like for example, my code is:
function addToUserGroupList() {
_root.qDomId('js-assignGroupArrBtn').disabled = true
for (var i = 0; i < selectedIds.length; i++) {
$.ajax({
type: "POST",
url: 'groupManage.ashx',
dataType: 'text',
data: 'type=getInfo&groupId=' + selectedIds[i],
success: function (result) {
if (result != '') {
this.groupName = result.split('&')[0];
this.groupNotes = result.split('&')[2];
userGroupList.push({ 'uid': parseInt(selectedIds[i]),
'name': this.groupName,
'adminStr': this.groupNotes
});
_root.userListObj.gourpInst.gourpTB(userGroupList);
}
},
error: function (XMLHttpRequest, status, errorThrown) {
alert('failed to add to user\'s group.');
}
});
}
_root.qDomId('js-assignGroupArrBtn').disabled = false;
selectedIds = [];
}
Why is that it calls out selectedIds = []; first before the Ajax Query?
Is it possible to let the ajax queries be finished before proceding to selectedIds = [];? Because it clears the array right before it's finished doing the stuffs. :/

First off, you really need to understand how an Ajax call is Asynchronous (that's what the "A" in Ajax stands for). That means that calling $.ajax() only starts the ajax call (it sends the request to the server) and the rest of your code happily continues running. Sometimes LATER after the rest of your code has executed, the success or error callback handler is called when the response comes back from the server. This is NOT sequential programming and must be approached differently.
The #1 thing this means is that ANYTHING that you want to have happen after the ajax call MUST be in the success or error handler or called from there. Code located right after the ajax call will be run long before the ajax call completes.
So, there are different ways to structure your code to work with this asynchronous concept. If you only want one asynchronous ajax call in flight at a time, you have to do this restructuring and can't use a simple for loop. Instead, you can create an index variable and in the completion function, increment the index and kick off the next iteration. Here's one way to code it:
function addToUserGroupList() {
_root.qDomId('js-assignGroupArrBtn').disabled = true
var i = 0;
function next() {
if (i < selectIds.length) {
$.ajax({
type: "POST",
url: 'groupManage.ashx',
dataType: 'text',
data: 'type=getInfo&groupId=' + selectedIds[i],
success: function (result) {
i++;
if (result != '') {
this.groupName = result.split('&')[0];
this.groupNotes = result.split('&')[2];
userGroupList.push({ 'uid': parseInt(selectedIds[i]),
'name': this.groupName,
'adminStr': this.groupNotes
});
_root.userListObj.gourpInst.gourpTB(userGroupList);
}
next();
},
error: function (XMLHttpRequest, status, errorThrown) {
alert('failed to add to user\'s group.');
}
});
} else {
// last one done
_root.qDomId('js-assignGroupArrBtn').disabled = false;
selectedIds = [];
}
}
// kick off the first one
next();
}

Related

Array of multiple ajax deferred calls processed in an asynchronous code block followed by synchronous final code block

I am relatively a newbie to jquery and ajax and am trying to use the concept of deferrals and promises to solve this problem I have.
I would like to do the following:
Call a list of URLS and process the result returned from the urls. I would like to first process the results in parallel, and then combine the processed results to give me a final result.
Th pseudo-code is as follows:
var deferredAjaxCalls = [];
for (var i = 0; i < jobsListLength; i++) {
deferredAjaxCalls.push(
$.ajax({
url:"/myurl",
method:"POST",
contentType:"application/json",
dataType:"json",
data:mydata,
success:function(result){
//Some code here that is performance intensive
}
});
}
$.when.apply(this,deferredAjaxCalls).done(function(){
for (var k=0; k< arguments.length;k++){
//combine the results of the individual results of the
// success part of all the ajax calls and execute some more
//code synchronously
}
}).fail( function (jqXHR, status, error) {
//Log failed status
});
Initially, I moved all of the code from the success part inside the $.when.apply().However, this resulted in very slow performance as there is a lot of intensive computation that is now executed synchronously. So I am looking for a way to execute part of the code independently, and the final piece synchronously
I did read about using promises, but could not find any example where promises are used with an array of ajax calls with intermediate processing before finally synchronising in the when.apply() block
What would be a good way to solve this problem?
Thanks!
Starting with an array jobsList, you probably want something like this :
var deferredAjaxCalls = jobsList.map(function(job) {
return $.ajax({
url: "/myurl",
method: "POST",
contentType: "application/json",
dataType: "json",
data: mydata
}).then(process);// where `process` is a function that accepts $.ajax's (data, textStatus, jqXHR) and returns a *single* value/object - the result of the processing. This will standardise the data delivered below by $.when() to its success handler.
});
$.when.apply(null, deferredAjaxCalls).then(function() {
// Due to `.then(process)` above, `arguments` are guaranteed to comprise one arg per ajax call.
// Otherwise you potentially have the problem reported here - http://stackoverflow.com/questions/12050160/
for (var k=0; k<arguments.length; k++) {
// Combine the results of the individual results of the success part of all the ajax calls and execute some more code synchronously.
}
// In this function deliver an error by returning `$.Deferred().reject(new Error('myReason'))`
return combined_result;
}, function(jqXHR, status, error) {
// This hander will receive multiple $.ajax() params, which are best normalised into a single Error object.
return new Error(status); // similar to .then(process) above, reduce $.ajax's error args to a single "reason".
}).then(null, function(err) {
// All errors delivered by code above arrive here as a js Error.
// But please note that, in jQuery <v3.0, any uncaught errors above will genuinely throw (to the console).
console.log(err.message);
});
You can try using deferreds:
var req_responses = [];
var deferreds = [];
for(var i in jobs) {
deferreds[i] = new $.Deferred();
}
for(var i in jobs) {
(function(i) {
$.ajax ({
url: ".",
type: "POST",
dataType: "json",
done: function(response) {
//process the response
req_responses[i] = response;
deferreds[i].resolve();
}
});
})(i);
}
$.when.apply(deferreds).then(function(os) {
//all the responses are in req_responses
//finish processing
alert("done");
});

Recursive function in javascript and ajax

I'm trying to do a little web in JavaScript + Ajax and I want to do it recursively. I've never used ajax before and the problem is I don't know to finish functions. The code looks like that:
var cont = 0;
var function1 = function (query) {
$.ajax({
url: '...',
data: {
.
.
.
},
success: function (response) {
instructions;
function2(param1, param2);
}
});
};
var function2 = function (query, param2) {
$.ajax({
url: '...',
data: {
.
.
.
},
success: function (response) {
instructions;
function3(param1, param2, param3);
}
});
};
var function3 = function (query, param2, param3) {
if (cont == 2) {
console.log("finish");
return;
}
var test = $.ajax({
url: '...',
data: {
.
.
.
},
success: function (response) {
if (...) {
cont++;
instructions;
var audio = new Audio(...);
audio.play();
audio.onended = function () {
instructions;
function3(query, param2, param3);
return;
};
} else {
instructions;
function3(query, param2, param3);
};
return;
}
});
return;
};
document.getElementById('search-form').addEventListener('submit', function (e) {
e.preventDefault();
function1(document.getElementById('query').value);
}, false);
So basically, when cont == 2I try to get out of javascript function3 with return; but some part of the program ( I don't know if the success: function (response) or the full javascript function3 ) is still running and instructions are being executed.
How could I solve this?
First off, the way to do this properly is to make use of jQuery's deferred objects.
As you have probably noticed, the program doesn't simply wait at the ajax request, and then proceed to the 'success' handler. This is because Javascript uses a non-blocking/waiting model. So you call $.ajax({params,...}), this sends the request, but whatever's after this will then immediately run, without waiting. Then, once the top level function has finished executing and nothing else is running, the response can be processed, and the 'success' handler is invoked.
So how to do this stuff properly? Start by arranging your request functions like this:
function doRequest1() {
return $.ajax({
url: '...',
data: {
.
.
.
}
});
}
function doRequest2(parameter) {
return $.ajax({
url: '...',
data: {
.
p: parameter
.
}
});
}
Notice that we aren't providing a success handler, but we are returning the value that $.ajax returns. This is a deferred object which is used to represent a request which has been sent, but for which a response hasn't been received/handled. You can attach a handler to the object like this:
var r1 = doRequest1();
r1.then(function() {
// Do stuff on success...
});
A nice thing about these objects is that they can be chained using 'then'.
'then' accepts a function which takes the value of the old request and produces a new request to do next:
var allRequests = doRequest1().then(function(result1) {
return doRequest2("hello");
});
The 'allRequests' variable is now a deferred object representing the result of doRequest2. How do you get this result? You use 'then()', just like any other deferred:
allRequests.then(function(result) {
alert("All requests completed. Result of last one: " + result);
});
Make sure that you understand how the result from 1 request can be used to set the parameters for the next one, or even decide which request to make next.
If you don't need one request's result to determine the next, rather, you just want to run a number of requests and wait for them all to complete, you can use a shortcut, 'when':
$.when(doRequest1(),doRequest2(), doRequest3()).then(function(result1,result2,result3) {
// All done
});
Another nice thing about deferreds is that they can be cancelled:
allRequests.abort();
Using the above, hopefully you can see how to restructure your code so you get a sequence of requests with a function to run after all 3 have completed.
Watch the value of your global variable cont through the flow of your program. It may be that it is (never) equal to 2 when function3() is called and that is why your program continues.

global variable does not changed after ajax call

I am using below code
var lockonscreens = 1;
jQuery(document).ready(function(e) {
var noOfSelection = 0;
if(lockonscreens == 0){
// some stuff
}
if(lockonscreens == 1){
// some stuff
}
});
function ajaxcall(){
jQuery.ajax({
url:
type:
data:
async: false,
success: function(data){
lockonscreens = data;
}
});
}
jQuery("#").click(function(){
ajaxcall();
});
I am using above code to get some data through ajax and set it to variable and depending on that variable a click event code may happen.
But on ajax call the global variable value doesn't get changed.
It remains the same even if the data changes in ajax.
Can anyone let me know what is the issue and how to correct it?
Remember that ajax is asynchronous, so if you call ajaxCall() and next an other function, ajax start the call to server and the function end.
When the server respond, the code after success: is executed.
Make sure you call the function in the success: function

node js : should be use alert to invoke the function?

i dont know what happen with my code..i have a Node.js that queries a MySQL db within the route and displays the result to the user. My problem is how do I run the queries and block until queries are done before redirecting the user to the page they requested?
if i add alert before call,function run normally and quick response..but if alert disable the function cant return any value,the function like freeze..
this user code to request value to nodejs
function fred(){ //request function from here to fblue
alert('fred called'); //if i disable alert,the function not return any value
get('id', function(datmovMar) {
var obj = JSON.parse(datmovMar);
var items = Object.keys(obj);
var output='';
items.forEach(function(item) {
output+=obj[item].something+'<br/>';
alert(output);
});
});
}
function get(id, callback) {
$.ajax('http://localhost:8000/' + id + '/', {
type: 'GET',
dataType: 'json',
success: function(data) { if ( callback ) callback(data); },
error : function() { if ( callback ) callback(null); }
});
}
and this code locate in node js
fblue(function(datmovMar){ //call function from here
res.write(JSON.stringify(datmovMar));
res.end('\n');
});
function fblue(callback){
var query = connection.query('SELECT something from table'),
pinMarker = [];
query
.on('error', function(err) {
console.log( err );
updateSockets( err );
})
.on('result', function( user ) {
pinMarker.push( user );
})
.on('end',function(){
if(connectionsArray.length) {
jsonStringx = JSON.stringify( pinMarker );
callback(jsonStringx);
}
});
}
i dont know why if alert disable the function cant run normally?
please help...
thanks
You're calling jQuery's $.ajax method which will create an asynchronous javascript request to your server.
This means that the control flow will continue right after you initiated the call to your server.
So you should not expect from fred() function to block until your request has been served, instead you need to rewrite your browser side javascript code in asynchronous way.
jQuery's $.ajax function by default runs asynchronously. That means the request won't be blocked while it's running, so subsequent lines of code will be immediately executed. With async calls, order of execution is not guaranteed.
You can 'cheat' a little bit here and specify the async option as follows:
$.ajax('http://localhost:8000/' + id + '/', {
type: 'GET',
dataType: 'json',
async: false,
success: function(data) { if ( callback ) callback(data); },
error : function() { if ( callback ) callback(null); }
});
That will force the $.ajax call to NOT return until it is completed. That's not really the JavaScript way of doing things, however, because you lose the efficiencies gained by asynchronous execution. As another KARASZI pointed out, you should write this asynchonously.

How to Stop execution of the JS Code after $.ajax call i.e. when server is processing the AJAX Request

I have a strange issue in JQuery AJAX..
My Steps sequence are as follows:
1) I have a JS Function which I am calling on Button Click Event:
function Click()
{
//I am performing some Validations then making an AJAX Request:
$.ajax({
type: "POST",
url: url,
context: window,
data: datatoPost,
contentLength: contentLength,
async: true,
success: function (response) {
callbackFn(response);
},
error: function (msg) {
this.error = msg;
}
});
// The callback function is called on Successfull AJAX Request
// i.e. callbackFn (See below)
// I am then checking the window.IsValid which I have set in below function;
if (window.IsValid == true) {
// Then Perform another AJAX Request
}
else {
// do nothing
}
}
function callbackFn(response)
{
if(response == 'Valid')
{
window.IsValid = true;
}
else
{
window.IsValid = false;
}
}
2) Now, The Problem is while server is processing the First AJAX Request then the code written after that i.e.
if (window.IsValid == true) {
// Then Perform another AJAX Request
}
else {
// do nothing
}
}
is executed
3) I get window.IsValid = false as first AJAX Request's callback function i.e. callbackFn(response) is not called yet and Even after a Valid response of first AJAX request my second ajax request is not getting executed as window.IsValid variable is not still got set in callback function as callback is not called yet due to server is processing the request.
Please help me I am stuck..
you should then use
async: false,
in you ajax function call. Which is not recomended. The better thing will be to use
if (window.IsValid == true) {
// Then Perform another AJAX Request
}
else {
// do nothing
}
}
within your callback function.
Because your post is asynchronous, the script continues to execute whilst the ajax request is being processed.
Instead, you need to move your tests for window.IsValid into the success function:
function Click()
{
//I am performing some Validations then making an AJAX Request:
$.ajax({
type: "POST",
url: url,
context: window,
data: datatoPost,
contentLength: contentLength,
async: true,
success: function (response) {
callbackFn(response);
if (window.IsValid == true) {
// Then Perform another AJAX Request
// best done as another function.
}
else {
// do nothing
}
},
error: function (msg) {
this.error = msg;
}
});
}

Categories