jQuery continue loop execution after ajax success - javascript

I have a jQuery ajax call in a loop. However I do not want those ajax calls to be made simultaneously, I need the first ajax call to finish before going on to the next.
for (var i = 0; i < options.length; i++) {
jQuery.ajax({
url: "ajax_file.php",
data: //some data based on DOM tree
success: function(data){
//some DOM manipulation
}
});
}
I want the loop to continue executing only after the DOM manipulation in SUCCESS was executed (because the ajax call depends on the DOM tree).
In theory I know I could set the ajax call to be async:false, but it is not recommended as it can freeze the browser.

Because async: false is always a bad idea, I'd recommend something like this:
var recur_loop = function(i) {
var num = i || 0; // uses i if it's set, otherwise uses 0
if(num < options.length) {
jQuery.ajax({
url: "ajax_file.php",
data: //some data based on DOM tree
success: function(data){
recur_loop(num+1);
}
});
}
};

Setting async to false will do that. Keep in mind that the web browser might lock up while the requests happen if you do them asynchronously.
jQuery.ajax({
async : false,
url: "ajax_file.php",
data: //some data based on DOM tree
success: function(data){
//some DOM manipulation
}
});

you can do something like this (pseudo-code):
var i =0;
doLoop();
function doLoop() {
//exit condition
if (i >= options.length) {
return;
}
//loop body- call ajax
$.ajax({
//...
success: function(data) {
//do your thing
i++;
//go to next iteration of the loop
doLoop();
}
});
}

Related

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

Wait for AJAX to finish before proceeding with the loop?

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();
}

Javascript - AJAX request inside loops

I'm using jQuery to send an AJAX request, retrieving data from a server.
That data is then appended to an element. This should happen 5 times, but it will always happen randomly either 3, 4, or 5 times. Basically, sometimes the loop will skip the AJAX request, but the majority of the time it catches it. How do I make sure it completes the request five times every time? and what is the reason behind this random behavior of skipping AJAX request?(side note. I've checked the request errors, but it never alerted of a request failure)
Here's my JS:
while (counter < 6) {
$.ajax({
url:'http://whisperingforest.org/js/getQuote.php',
async: false,
dataType: 'jsonp',
success:function(data){
$('.quoteList').append('<li>' + data +'</li>');
totalQuotes++;
}
});
counter++;
}
P.s. this happens on a button press.
Don't do it synchronously. Use the callback. Here is a demo for you: http://jsfiddle.net/y45Lfupw/4/
<ul class="quoteList"></ul>
<input type="button" onclick="getData();" value="Go Get It!">
<script>
var counter = 0;
window.getData=function()
{
/* This IF block has nothing to do with the OP. It just resets everything so the demo can be ran more than once. */
if (counter===5) {
$('.quoteList').empty();
counter = 0;
}
$.ajax({
/* The whisperingforest.org URL is not longer valid, I found a new one that is similar... */
url:'http://quotes.stormconsultancy.co.uk/random.json',
async: true,
dataType: 'jsonp',
success:function(data){
$('.quoteList').append('<li>' + data.quote +'</li>');
counter++;
if (counter < 5) getData();
}
});
}
</script>
Setting async to false blocks the main thread (responsible for
executing JavaScript, rendering the screen, etc) and waits for the XHR
to complete.
This is almost always a terrible idea. Users don't like unresponsive
UIs. (https://stackoverflow.com/a/20209180/3112803)
Just search stackoverflow for ajax async: false and you will find MANY good explanations on this. Everyone will discourage you from using async:false. Here's is a great explanation: https://stackoverflow.com/a/14220323/3112803
Very interesting methods provided by jQuery when you are executing loops of asyncroniouse request and detect all ajax request completed or not. It is possible by using
var users=["a","b","c","d","e","f","g","h"];
var async_request=[];
var responses=[];
for(i in users)
{
// you can push any aysnc method handler
async_request.push($.ajax({
url:'', // your url
method:'post', // method GET or POST
data:{user_name: users[i]},
success: function(data){
console.log('success of ajax response')
responses.push(data);
}
}));
}
$.when.apply(null, async_request).done( function(){
// all done
console.log('all request completed')
console.log(responses);
});
Here $.when provides a way to execute callback functions based on zero
or more objects, usually Deferred objects that represent asynchronous
events.
apply() converts array elements as different arguments in
function
$.done is call function after all async. request are
completed.
You can use ES6 async/await Promises like this
function fromServer(){
return new Promise((resolve, reject) => {
$.ajax({
url:'http://whisperingforest.org/js/getQuote.php',
async: false,
dataType: 'jsonp',
success:function(data){
resolve(data)
}
});
})
}
var totalQuotes = 0;
async function domManipulation(){
while (counter < 6) {
var data = await fromServer();
$('.quoteList').append('<li>' + data +'</li>');
totalQuotes++;
}
}
domManipulation()
JSFIDDLE

Multiple AJAX calls using the same AJAX functions

I am looking to fire off several jQuery AJAX requests in quick succession, so the response will not come before the next request. However, I do want to handle each one of these responses with the success function.
With the following code, the first two responses will be ignored and only the last one will respond.
$('#button').click(function() {
var num = 3;
for(var i=0;i<num;i++)
ajaxCall(i);
}
function ajaxCall(data){
$.ajax({
url: '/echo/html/',
success: function(msg) {
alert(msg);
}
});
}
However I am trying to make it so that all three alerts would show up. It seems that each time the ajaxCall function is called it uses the same 'object' as it did the previous time instead of instantiating a new one, which is what I want to do.
Try this (using Deferred Object)
$('#button').click(function() {
var num = 3;
for(var i=0;i<num;i++) {
ajaxCall(i).done(function(data)
{
alert(data)
}
);
}
});
function ajaxCall(data){
return $.ajax({
url: '/echo/html/'
});
}

Ajax jquery synchronous callback success

I have this function that makes an ajax call. I'm describing the problem in the last chunk of code comments.
function doop(){
var that = this;
var theold = "theold";
var thenew = "thenew";
$.ajax({
url: 'doop.php',
type: 'POST',
data: 'before=' + theold + '&after=' + thenew,
success: function(resp) {
if(resp == 1) {
$(that).siblings('.theold').html(thenew);
}
}
});
// I have some code here (out of the ajax) that **further** changes
// the .theold's html beyond what it was changed inside ajax success
// but the change depends on whether the resp (inside the success
// function) returned 1 or not, so this code out here depends on the ajax
// so it looks like I have to turn this ajax call into a sync ajax
return false;
}
Based on the problem as described in the code comments, what changes are best for this situation?
You need to set async: false for synchronous requests like this:
function doop(){
var that = this;
var theold = $(this).siblings('.theold').html();
var thenew = $(this).siblings('.thenew').val();
$.ajax({
async: false,
url: 'doop.php',
type: 'POST',
data: 'before=' + theold + '&after=' + thenew,
success: function(resp) {
if(resp == 1) {
$(that).siblings('.theold').html(thenew);
}
}
});
// some other code
return false;
}
see here for details
Either set the Ajax call to synchronous as stefita pointed out, or just move your code into the success callback. Why can't you do this? Even if it's another Ajax call it still can be done - you can nest them. With the information given by you so far (I can't see the problematic code, nor I have enough domain knowledge about your project) I don't see a problem, really.
I prefer to use callback to do the job because it achieves exactly the same result without actually making it synchronous. I use success:callback and then pass in the callback as a parameter.
function getData(callback) {
$.ajax({
url: 'register/getData',
data: "",
dataType: 'json',
success: callback
});
}
I then call this function like this:
getData(function(data){
console.log(data); //do something
});

Categories