Multiple jquery ajax request - ways to handle it - javascript

If there is jquery ajax loading and I fire another ajax by quickly clicking the button, it kind of gets stuck. How can I handle multiple requests fired together?
How do I do following?
Discard/abort all previous requests and only process the latest one.
Do not allow new request until previous request completes (variation: can be same ajax request or any new ajax request from the page).

AJAX is Asynchronous. So you can fire them at the same time.
Or in the success callback (or .done() callback), you can call one request after another. So it will be easy to manage your issue (you click the button but get stucked), because you can control.
$.ajax({
url: "http://..."
})
.done(function( data ) {
// Other AJAX call
// or restore disabled elements
// while you were receiving the response.
});
If you want a work-around, just tell me.

you can use ajax "beforeSend" to lock the current request.So that user can send a new request only if the previous one is done. As for the process sequence, you can use a global value to store data and always assign it with the new response value.
function request(callback){
if(!$btn.hasClass('disabled')){
$.ajax({
type:'...',
url:'...',
beforeSend:function(){
$btn.addClass('disabled');//so that user cannot send a new request
},
success:function(data){
window.g_data = data;
callback && callback()//success callback
$btn.removeClass('disabled');
}
})
}
}
function callback(){
//process window.g_data
}

Have a look at this library:
Async is a utility module which provides straight-forward, powerful functions for working with asynchronous JavaScript.
Async

Related

Waiting for success of Jquery.trigger

I have a form that has a set of drill-downs so one drop down will fill in another. I have a script set up to remember the form values and reset them for that page. My issue comes in when I execute on the trigger for the element, I can't figure out any way to wait on the other dropdown to refresh and then setting its value. Is there any way I can wait for the success result of a function that's kicked off by trigger('change') (or similar function) besides listening for the ajax request. My fall back plan is to do this with cookies and then fill in the form server side. Which might look better anyway, I'm just wondering if it can be done.
I have it saving the values from each drop down and loading them when I get back, I'm wondering if there's some way I can
listen for the ajax call in dropdown_a to finish if I load the value from session storage and call $('#dropdown_a').trigger('change')
the more I think about it I'd probably have to store some sort of value in the program that tracks any request made so I can await them
which would defeat the purposes of the self contained script I have for this
$('#dropdown_a').on('change', function() {
//Ajax call I want to wait for
$.ajax({
url: 'someendpoint',
data: 1,
success: function(response) {
util.fillsInSelectBox(response, $('#dropdown_b'));
},
error: function() {
showErrorModal();
}
});
});
$('#dropdown_b').on('change', function() {
$('#table').bootstrapTable('refresh');
});

Queue ajax requests if another one is in progress

I have an application that gets an authentication token in every service call's response and it is supposed to send the previous token as a parameter for the next call otherwise user will be unauthorized. And once the token is mismatched, all the other calls fail.
To make sure that the tokens are not mismatched, i have added loaders on my screen and i display them as soon as an ajax call is initiated and keep the loading overlay on screen until the response is not received otherwise the user could click on any other link which would result in another ajax call.
But still, i think the loader mechanism is prone to loopholes. Is there any way to check if any ajax call is in progress, then queue the new one and the queued one shall wait for the initiated ones response because it would need the token returned from its response as its new request parameter.
I just worked on a project where I did this. Let's say you've got your AJAX function, foo.ajax( url, callback ).
You need a way to package all the details that would go out in an AJAX request. So you make a function foo.ajaxRequest(url) and a list of requests, foo.requestList = [] and use them like this:
foo.ajaxRequest = function( url ) {
foo.requestList.push(this);
var callback = function( data ) {
if ( foo.requestList.length ) {
foo.requestList.shift().run( data );
}
}
this.run = function( dataFromPreviousAjax ) {
foo.ajax( url + "?key=" + dataFromPreviousAjax, callback );
}
if ( !foo.requestList.length ) {
foo.ajax( url, callback );
}
}
and any time you want to make some requests, you write
new foo.ajaxRequest("http://stackoverflow.com/pingback.php");
new foo.ajaxRequest("http://stackoverflow.com/pingback.php");
and now suppose the first request returns a key of 12345, the second request will now run and call the url "http://stackoverflow.com/pingback.php?key=12345".
Obviously you'd want to do more stuff with the return value in the callback function inside foo.ajaxRequest, but this should get you started.

Wait unitl ajax and its callback function finish

I am building a web app that allows users to perform a number of actions simultaneously. For example, user can open a list, delete a list, or add a new list.
Each action makes an ajax call and executes a callback function to update UI upon success. I want to make sure these actions are performed in a serialized manner, so that the UI does not go out of sync. For example, if user opens a list, but deletes the list a fraction of a second later, depending on which ajax call finsihes first, it may display the list which is supposed to be now deleted.
To accomplish this, for each action, I want to wait until an ajax call and its callback function are finished. How can I achieve this?
If you're using jQuery the .always() callback is called after .done()/.fail().
$.ajax("example.php")
.done(function() {
alert("success");
})
.fail(function() {
alert("error");
})
.always(function() {
alert("complete"); //Called after done/fail callbacks
});
With Jquery, you could add async: false to your Ajax call or use Jquery deferred to make sure an action is only issued after the Ajax calls are finished (assuming you use Jquery).
If you have multiple Ajax requests, an example could look like:
$.ajax({url: url}).pipe(function() {
// some ajax stuff
return $.ajax({});
}).pipe(function() {
// some more ajax stuff (3rd request)
return $.ajax({});
}).done(function() {
// done with all ajax requests...
});

Queue multiple AJAX requests, waiting for response and not freezing browser? [duplicate]

This question already has answers here:
Sequencing ajax requests
(10 answers)
Closed 9 years ago.
I am working a script, I need to loop an array of AJAX requests:
$('#fetchPosts').click(function(){
for(var i=0; i < link_array.length; i++) {
settings = {
// some object not relevant
}
var status = main_ajaxCall(settings, i); // ajax call
}
});
function main_ajaxCall(settings, i) {
$.ajax({
type: "POST",
url: "../model/insert.php",
data:{obj_settings: settings},
dataType: "json",
cache: false,
success: function (data) {
// some handeling here
return 0;
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
return 1;
},
};
Why does the AJAX requests fire instantly? It does not seem to wait for a response from model/insert.php, is there any way to force it to wait for a response before firing the next AJAX request?
EDIT 1:
It seems I wasnt clear, sorry, I dont want it to wait, I want to queue up the calls.
I cant make the call in one request, this is impossible in my current situation.
Set async to false if you want to wait for a response (default: true)
$.ajax({
async: false,
...
http://api.jquery.com/jQuery.ajax/
If you do not want blocking, you can set a success handler function using .ajaxComplete(), and you have to keep track of active AJAX connections if you want to wait for all to complete - How to know when all ajax calls are complete
The best solution would be to minimize the number of AJAX requests to one. If you have to make a loop of AJAX requests, the logic could be simplified somewhere (put that in the server perhaps?)
EDIT 1: (In response to OP edit)
If you want to queue the AJAX requests, this question has been answered before here:
Sequencing ajax requests
Queue ajax requests using jQuery.queue()
You could also use these libraries (all you needed to do was Google):
https://code.google.com/p/jquery-ajaxq/
http://codecanyon.net/item/ajax-queue-jquery/full_screen_preview/4903957
http://schneimi.wordpress.com/2008/03/10/multiple-ajax-requests-problems-and-ajaxqueue-as-solution/
It fires instantly and doesn't wait around because that's what AJAX does best (The first A stands for asynchronous).
The request to a server could take a long time to respond, and in most cases, don't want user's browser's freezing up or stopping them from doing anything else. If you do, you could probably just use a normal request.
This is the reason you give it functions for success error, so it can call them when the server responds.
If you want nothing to be able to happen in the browser while you're calling insert.php, you could drop an overlay (eg. dark div) over everything with a loading image and remove it on success.
Maybe replace the $('#fetchPosts') element with "loading..." text and then reverse it when done. Hiding visibility of the fetchPosts element and adding a different "loading.." element is a nice way.
Your AJAX call will wait for a response from the server, but wil do so asynchronously. That is, your script will continue to execute rather than block the browser while the server responds. When the server responds (or when the request times out - usually several seconds) your success: or error: functions will then execute.
The effect of your code here is to create several concurrent requests based on the link_array length.
You could specify async:false in your AJAX call, but this would freeze the browser while all the AJAX calls are made.
You should rewrite your code to execute all the handling as part of your success: function. I'd recommend you rewrite your code to assemble all your request into one, and make one AJAX call rather than several, and have the server return all the responses as one block. I can't suggest exactly how you do that - it's implementation dependent.
EDITED:
In response to your clarification, if you want them to be called in order, you'll need the success function to call the next one. You'll then have a chain of success calls the next, whose success calls the next, whose success calls the next.. etc until the last one which does the final processing. One way would be to pass the call number to the success function.

How do you make javascript code execute *in order*

Okay, so I appreciate that Javascript is not C# or PHP, but I keep coming back to an issue in Javascript - not with JS itself but my use of it.
I have a function:
function updateStatuses(){
showLoader() //show the 'loader.gif' in the UI
updateStatus('cron1'); //performs an ajax request to get the status of something
updateStatus('cron2');
updateStatus('cron3');
updateStatus('cronEmail');
updateStatus('cronHourly');
updateStatus('cronDaily');
hideLoader(); //hide the 'loader.gif' in the UI
}
Thing is, owing to Javascript's burning desire to jump ahead in the code, the loader never appears because the 'hideLoader' function runs straight after.
How can I fix this? Or in other words, how can I make a javascript function execute in the order I write it on the page...
The problem occurs because AJAX is in its nature asynchronus. This means that the updateStatus() calls are indeed executed in order but returns immediatly and the JS interpreter reaches hideLoader() before any data is retreived from the AJAX requests.
You should perform the hideLoader() on an event where the AJAX calls are finished.
You need to think of JavaScript as event based rather than procedural if you're doing AJAX programming. You have to wait until the first call completes before executing the second. The way to do that is to bind the second call to a callback that fires when the first is finished. Without knowing more about the inner workings of your AJAX library (hopefully you're using a library) I can't tell you how to do this, but it will probably look something like this:
showLoader();
updateStatus('cron1', function() {
updateStatus('cron2', function() {
updateStatus('cron3', function() {
updateStatus('cronEmail', function() {
updateStatus('cronHourly', function() {
updateStatus('cronDaily', funciton() { hideLoader(); })
})
})
})
})
})
});
The idea is, updateStatus takes its normal argument, plus a callback function to execute when it's finished. It's a reasonably common pattern to pass a function to run onComplete into a function which provides such a hook.
Update
If you're using jQuery, you can read up on $.ajax() here: http://api.jquery.com/jQuery.ajax/
Your code probably looks something like this:
function updateStatus(arg) {
// processing
$.ajax({
data : /* something */,
url : /* something */
});
// processing
}
You can modify your functions to take a callback as their second parameter with something like this:
function updateStatus(arg, onComplete) {
$.ajax({
data : /* something */,
url : /* something */,
complete : onComplete // called when AJAX transaction finishes
});
}
I thinks all you need to do is have this in your code:
async: false,
So your Ajax call would look like this:
jQuery.ajax({
type: "GET",
url: "something.html for example",
dataType: "html",
async: false,
context: document.body,
success: function(response){
//do stuff here
},
error: function() {
alert("Sorry, The requested property could not be found.");
}
});
Obviously some of this need to change for XML, JSON etc but the async: false, is the main point here which tell the JS engine to wait until the success call have returned (or failed depending) and then carry on.
Remember there is a downside to this, and thats that the entire page becomes unresponsive until the ajax returns!!! usually within milliseconds which is not a big deals but COULD take longer.
Hope this is the right answer and it helps you :)
We have something similar in one of our projects, and we solved it by using a counter. If you increase the counter for each call to updateStatus and decrease it in the AJAX request's response function (depends on the AJAX JavaScript library you're using.)
Once the counter reaches zero, all AJAX requests are completed and you can call hideLoader().
Here's a sample:
var loadCounter = 0;
function updateStatuses(){
updateStatus('cron1'); //performs an ajax request to get the status of something
updateStatus('cron2');
updateStatus('cron3');
updateStatus('cronEmail');
updateStatus('cronHourly');
updateStatus('cronDaily');
}
function updateStatus(what) {
loadCounter++;
//perform your AJAX call and set the response method to updateStatusCompleted()
}
function updateStatusCompleted() {
loadCounter--;
if (loadCounter <= 0)
hideLoader(); //hide the 'loader.gif' in the UI
}
This has nothing to do with the execution order of the code.
The reason that the loader image never shows, is that the UI doesn't update while your function is running. If you do changes in the UI, they don't appear until you exit the function and return control to the browser.
You can use a timeout after setting the image, giving the browser a chance to update the UI before starting rest of the code:
function updateStatuses(){
showLoader() //show the 'loader.gif' in the UI
// start a timeout that will start the rest of the code after the UI updates
window.setTimeout(function(){
updateStatus('cron1'); //performs an ajax request to get the status of something
updateStatus('cron2');
updateStatus('cron3');
updateStatus('cronEmail');
updateStatus('cronHourly');
updateStatus('cronDaily');
hideLoader(); //hide the 'loader.gif' in the UI
},0);
}
There is another factor that also can make your code appear to execute out of order. If your AJAX requests are asynchronous, the function won't wait for the responses. The function that takes care of the response will run when the browser receives the response. If you want to hide the loader image after the response has been received, you would have to do that when the last response handler function runs. As the responses doesn't have to arrive in the order that you sent the requests, you would need to count how many responses you got to know when the last one comes.
As others have pointed out, you don't want to do a synchronous operation. Embrace Async, that's what the A in AJAX stands for.
I would just like to mention an excellent analogy on sync v/s async. You can read the entire post on the GWT forum, I am just including the relevant analogies.
Imagine if you will ...
You are sitting on the couch watching
TV, and knowing that you are out of
beer, you ask your spouse to please
run down to the liquor store and
fetch you some. As soon as you see
your spouse walk out the front door,
you get up off the couch and trundle
into the kitchen and open the
fridge. To your surprise, there is no
beer!
Well of course there is no beer, your
spouse is still on the trip to the
liquor store. You've gotta wait until
[s]he returns before you can expect
to have a beer.
But, you say you want it synchronous? Imagine again ...
... spouse walks out the door ... now,
the entire world around you stops, you
don't get to breath, answer the
door, or finish watching your show
while [s]he runs across town to
fetch your beer. You just get to sit
there not moving a muscle, and
turning blue until you lose
consciousness ... waking up some
indefinite time later surrounded by
EMTs and a spouse saying oh, hey, I
got your beer.
That's exactly what happens when you insist on doing a synchronous server call.
Install Firebug, then add a line like this to each of showLoader, updateStatus and hideLoader:
Console.log("event logged");
You'll see listed in the console window the calls to your function, and they will be in order. The question, is what does your "updateStatus" method do?
Presumably it starts a background task, then returns, so you will reach the call to hideLoader before any of the background tasks finish. Your Ajax library probably has an "OnComplete" or "OnFinished" callback - call the following updateStatus from there.
move the updateStatus calls to another function. make a call setTimeout with the new function as a target.
if your ajax requests are asynchronous, you should have something to track which ones have completed. each callback method can set a "completed" flag somewhere for itself, and check to see if it's the last one to do so. if it is, then have it call hideLoader.
One of the best solutions for handling all async requests is the 'Promise'.
The Promise object represents the eventual completion (or failure) of an asynchronous operation.
Example:
let myFirstPromise = new Promise((resolve, reject) => {
// We call resolve(...) when what we were doing asynchronously was successful, and reject(...) when it failed.
// In this example, we use setTimeout(...) to simulate async code.
// In reality, you will probably be using something like XHR or an HTML5 API.
setTimeout(function(){
resolve("Success!"); // Yay! Everything went well!
}, 250);
});
myFirstPromise.then((successMessage) => {
// successMessage is whatever we passed in the resolve(...) function above.
// It doesn't have to be a string, but if it is only a succeed message, it probably will be.
console.log("Yay! " + successMessage);
});
Promise
If you have 3 async functions and expect to run in order, do as follows:
let FirstPromise = new Promise((resolve, reject) => {
FirstPromise.resolve("First!");
});
let SecondPromise = new Promise((resolve, reject) => {
});
let ThirdPromise = new Promise((resolve, reject) => {
});
FirstPromise.then((successMessage) => {
jQuery.ajax({
type: "type",
url: "url",
success: function(response){
console.log("First! ");
SecondPromise.resolve("Second!");
},
error: function() {
//handle your error
}
});
});
SecondPromise.then((successMessage) => {
jQuery.ajax({
type: "type",
url: "url",
success: function(response){
console.log("Second! ");
ThirdPromise.resolve("Third!");
},
error: function() {
//handle your error
}
});
});
ThirdPromise.then((successMessage) => {
jQuery.ajax({
type: "type",
url: "url",
success: function(response){
console.log("Third! ");
},
error: function() {
//handle your error
}
});
});
With this approach, you can handle all async operation as you wish.

Categories

Resources