How JQuery Ajax works? - javascript

I am trying to send data from JQuery Ajax to a Generic Handler that calculates something and returns a result. The Ajax request is made inside a for loop at JQuery end. The code looks something like this:
function send(Handler, ids) {
var URL = "http://" + window.location.host + "/Handlers/" + Handler + ".ashx";
var i;
for (i = 0; i < 10; i++) {
var cur = $('.' + ids[i]);
$.ajax({
url: URL,
type: "POST",
data: JSON.stringify({
Data: cur
}),
dataType: "json",
cache: false,
beforeSend: //my before send code,
success: //my success code,
error: //my error code
});
}
alert('Done!');
}
I placed 3 breakpoint in Visual Studio 2012 at line:
$.ajax({
this
alert('Done!');
And third breakpoint at first line in the Generic Handler.
Now, when I try to execute this code, the Ajax works nicely in async way. But, when it reaches the first breakpoint, stops there and then I resume it, instead of reaching the Generic Handler's breakpoint, it continues the loop and goes back to first breakpoint. Then after it reaches the second breakpoint it then stops at generic handler's break point again and again for each value.
So, does that mean that Ajax first collects all the ajax requests and then after the for loop it executes them together?

Javascript is single threaded and non-blocking. This means that in the first iteration won't wait for the ajax call to be completed, it will go back and start the second iteration, and so on.
So, no it doesn't executes them all together. It definately starts the ajax calls in the order of the loop but there is no way to tell what will end first. It might make all the ajax calls and then get an answer (doesn't mean it is the answer of the first iteration), or in the middle of a loop it might be getting answers.

If I am understanding you correctly, you just answered your own question. Ajax is working asynchronously meaning the for loop starts and fires out ajax requests, and continues the loop (the ajax request DOES NOT block)
Therefore it is very likely that the js is performing a loop of code before the request reaches your url (as this has to create a network call)
That said, what are you doing in your beforeSend method? maybe this is making it take enough time that it can perform all iterations of the loop before sending the first request?
To answer your question, no it shouldn't be waiting for the for loop to finish in order to send off the requests, it should be initiating the process as soon as you have made the call

Related

Spinner button that starts spinning when function is called and stops when it ends

I'm trying to make a spinner button that will spin while I make an AJAX request and stop when the answer is received.
I've got the AJAX handled but the spinning doesn't seem to work with the following code:
function refresh (id){
var iconElem = document.getElementById("spinner" + id);
iconElem.classList.add('fa-spin');
sleep(5000);
var buttonRefresh = document.getElementById("refreshButton" + id);
buttonRefresh.classList.remove("fa-spin");
};
Note : I have replaced the ajax function with a sleep (implemented elsewhere, but it works like like it should) since I am in a non-php environment.
What happens here is that the the class "fa-spin" is being added while the sleep is over, even though it comes after in the code... Am I missing some kind of "refresh" that I need to execute in order to make the added class effective ?
You need to stop the spinning in the completion callback of the ajax call as it is a async call.
What you are doing here is starting and then immediately stopping the spinner before the ajax call even finishes.
$.ajax({
url: "test.html",
cache: false,
success: function(html){
// stop the spinner here
}
});
Here is the simplest solution with a callback:
function sleep(callback,timeout){
setTimeout(callback,timeout)
}
sleep(() => {
//stop spinner here
},200)
Anyways, I suggest you to read more here
If you are doing an ajax request, you can also use the async:false header to make your request synced, and then your code should work.
Changes to the style or content of the document become effective only when the JavaScript function finishes and returns to the main event loop. Therefore, assuming your sleep() function works as expected (by doing a busy wait or something like that, although that is not actually sleeping), you can only see the total effect of all changes when the function returns. If you follow the advice of the other answers and remove the style in the callback of the AJAX call, you will be fine.

Understanding asynch behaivor of javascript with an example

I'm completely new in javascript and I'm trying to understand its asynch nature. For this purpose here is my sample code :
$("#calculate-similarity").click(function(){
// assume input is an array whose length is larger than 0
var requestData={"uris":input,"limit":100};
client=new Ajax(requestData);
alert('inside .click function');
})
Ajax=function(requestData){
alert('inside ajax');
$.ajax({
url: 'http://localhost:8080/',
type:'POST',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify(requestData),
xhrFields: {
withCredentials: true
}
}).done(function(data) {
$("#ws-results").children().detach();
$("#ws-results").append('<table id="my-final-table"><thead><th>fname</th><th>furi</th><th>sname</th><th>suri</th><th>similarity</th></thead><tbody></tbody></table>');
$('#my-final-table').dynatable({
dataset: {
records:data
}
});
});
}
Now, above, I'm creating new Ajax() and inside of it, I'm making a ajax request. As far as I know its asynch event. Therefore, I though that, this request should be completed first of all, and then my other javascript lines (alert('inside .click function')) should be executed. In other words, I would expect :
1) alert inside ajax
2) show my datatable on the browser
3) alert inside .click function
However, I got with the following order :
1) alert inside ajax
2) alert inside .click function
3) show table on the browser
So, what do you suggest me to understand these concepts ? I've a solid background with several programming languages like c++ and java but this is my first time with web development and javascript.
EDIT
If I modify my .click function like below, do you say first of all always 10000 times hello will be printed out and then table will be shown ? Or table would be shown somewhere at the middle of logging ? I mean when the response comes, engine should wait first in order to show it ?
Modified code : (Let's remove all of the alert statements)
$("#calculate-similarity").click(function(){
// assume input is an array whose length is larger than 0
var requestData={"uris":input,"limit":100};
client=new Ajax(requestData);
for(var z=0;z<10000;z++){
console.log(z+'hi!');
}
})
As far as I know its asynch event. Therefore, I though that, this request should be completed first of all, and then my other javascript lines should be executed.
That is exactly the opposite of what it means.
The Ajax function will run. It will trigger an HTTP request. The Ajax function will finish. alert will run.
At some point in the future, the HTTP response will arrive and the done event handler will fire.
This is exactly the same principle as:
alert(1);
$("#calculate-similarity").click(function(){ alert(2); });
alert(3);
JavaScript doesn't wait for you to click on calculate-similarity before firing alert(3).
If I modify my .click function like below, do you say first of all always 10000 times hello will be printed out and then table will be shown ? Or table would be shown somewhere at the middle of logging ? I mean when the response comes, engine should wait first in order to show it ?
JavaScript won't interrupt a running function in order to execute a different (event handler) function. It will wait until it isn't busy before it goes looking for events.
new Ajax is object instantiation and it's synchronous. Therefore you get inside ajax as the first result because it happens when your Ajax object is instantiated, not to be confused with when the Ajax request is fired.
alert is executed synchronously, so that's the second thing you get.
$.ajax which wraps around XMLHttpRequest, responsible for firing the actual ajax request, is the only async part in your code and its result, which is encapsulated inside done, is what you get last.
In other words, I think the confusion comes from the fact that you introduce another layer of abstraction called new Ajax() which provide little actual value and a lot of confusion :P. inside ajax signal inside the instantiation of your Ajax object, not the firing of the actual request.
I'll try my best to explain it. Think of this more as an analogy, it's not exactly what's going on but I think it might help you understand:
alert('inside ajax'); - this is a blocking call, it will run and wait for you to click OK.
Then when you call Ajax, what you're essentially doing is saying "go make this web request when you have a chance, and when it finishes call my done method." That's a network operation. It could finish in 1 second, it could take many seconds. Rather than freezing up the whole browser, this is done "in the background." So that makes the UI remains responsive. At some point in the future the network request will finish. When it does, the function you specified in done will get called to let you know it finished. Think of making the Ajax request as adding it to a queue rather than actually connecting to the network. When the browser gets to it it will execute your request and wait for the server to respond. When it does, it will signal you to let you know.
Next you alert('inside .click function'); which displays the alert and blocks.
Like I said, that's not a technically accurate description of what's going on, but I'm hoping it helps you understand the principle of it.

Detecting When Javascript is Done Executing

Is there an event in javascript that I could bind some sort of listener to that will tell me when all javascript/jQuery/Ajax is done executing on the page? The page will not be loading/unloading/reloading, etc between the time the execution begins and the time that I need the listener to "listen", so those events don't work. The page literally is not doing anything. The button is clicked and some javascript functions fire which contain Ajax calls to web services. After all have finished, I want to change window.location. But window.location is changing before the web services have finished in my case.
Currently using setTimeout to achieve this, but as sometimes the code needs more time to run than normal, sometimes the window.location is firing before all the other javascript has finished. Simply put
<input type = "button"... onclick="doThis();";
function doThis() {
try{
//Contains AJAX calls to web services which is mainly what screws up my timing since it may still be trying to execute stuff when the redirect statement happens
}
catch (e) {
}
//Currently doing setTimeout(redirect, 10000);
//Would like to simply detect when all of the above is done and then redirect.
}
Edit: Left out a crucial piece of info. The AJAX calls are in a for loop. The use of variables and success callbacks hasn't been working so well for me as by the time my success callback is executing, my variables have taken on new values in the for loop.
What you are trying to achieve is a classical concurrent programming problem. It is solved by the use of a barrier.
To put it simply, you need to:
Count how many calls you've done.
Set a callback on all AJAX completion events.
Make that callback decrement the number of calls.
The callback checks whether the number of calls has reached zero or not. If yes, then your final code (here, redirect) is called.
The actual implementation is left as an exercise to the reader :)
Hint: embed AJAX calls into a function that handles all counter incrementation and callback setting.
What I do:
Create a variable that represents the number of outstanding AJAX calls.
Before making an AJAX call, increment the variable.
At the end of the code that completes an AJAX call, call a function (e.g. ajaxComplete).
ajaxComplete should decrement the count. When it reaches zero, you know all your calls are complete.
Assuming you're using jQuery.ajax, it sounds like you're looking for ajaxStop.
Why don't you try using something like the Underscore library's after function in the callbacks?
var done = _.after(3, function() {
window.location = 'http://example.com';
});
$.ajax({
url: '/tic',
success: function() {
done();
}
});
$.ajax({
url: '/tac',
success: function() {
done();
}
});
$.ajax({
url: '/toe',
success: function( data ) {
done();
}
});
You should check for the response from AJAX call, and only in that response do redirect. This way you will avoid doing redirect while AJAX was still executing.

jquery ajax async false causes click event issue

I have a script that runs through a multi-level array and each time calls a new ajax GET command to a php file with part of that array as the data.
Pretty basic...
for(var x=0; x<cities.length; x++){
for(var u=0; u<links.length; u++){
$.ajax({
url: "dontneedtoknow.php?city=" + cities[x] + "&link=" + links[u],
type: 'GET',
async: false,
cache: false,
timeout: 30000,
error: function(){
return true;
},
success: function(data){
//just appending data to page
}
});
}
}
I'd like to be able to have click() events and the ability to STOP this for loop but when this loop is going I can't do ANYTHING because of the async false.
I need the async false because I want the data to be appended as each function completes for a reason.
I have tried .live() but that doesn't seem to work...
Ideas?
When async is false, the entire browser* will be hung. You cannot do anything during a synchronous Ajax call other than waiting for the call to finish.
If you want to be able to stop the loop, you must use asynchronous calls.
See also:
What does "async: false" do in jQuery.ajax()?
IE7 hangs when using (to much) ajax calls with async: false
How to make all AJAX calls sequential?
That last link especially might be useful (if I understand what you're trying to accomplish here).
*unless you're in Chrome (then it's just the current page)
Why make that many calls to the server? That seems very inefficient to me.
Is there a reason you can not change the service you are calling to receive a list of items and return it? It would involve one Ajax call and the server side code can make sure the data is processed in order.

Does this JS Code work as expected?

Every 3 seconds I make an AJAX POST request to get the status of a process. This works great.
When the process reaches 100% a call back function executes(indicated below) to add new elements to the page and then it cancels the setTimeout method that use to continuously get the progress every 3 seconds. However, I have been told by my users it sometimes fails to cancel and the new elements are not added to the page and I've been that it get stuck at showing "100%".
I have tested this again and again and it never gets stuck for me. The code also looks ok, but my JavaScript skills are not great so I was hoping someone could point out if there is potential of this problem happening?
I have commented the code, apologies its very long. I have tried to reduce it.
function convertNow(validURL){
startTime = setTimeout('getStatus();', 6000);
//AJAX CALL TO RUN PROCESS
$.ajax({
type: "GET",
url: "main.php",
data: 'url=' + validURL + '&filename=' + fileNameTxt,
success: function(msg){
//ON SUCCESS CLEAR SETTIMEOUT AND SHOW ELEMENTS (text)
clearTimeout(continueTime);
clearTimeout(startTime);
$("#loading").hide("slow");
$("#done").html("Done");
}//function
});//ajax
}//function convertNow
function getStatus(){
//AJAX CALL TO GET STATUS OF PROCESS
$.ajax({
type: "POST",
url: "fileReader.php",
data: 'textFile=' + fileNameTxt,
success: function(respomse){
textFileResponse = respomse.split(" ");
$("#done").html("Processing...");
}
});//ajax
clearTimeout(continueTime);
if(textFileResponse[0]=='100.0%'){
clearTimeout(continueTime);
}
else{
clearTimeout(startTime);
continueTime = setTimeout('getStatus();', 3000);
}
}
There's probably a parsing error in the textFileReponse[0]=='100.0%' in some edge cases, with the value in the response not equaling exactly 100.0% (maybe there's extra whitespace, or maybe there are some minor differences on some platforms, etc...). This would cause the code to fall through to the else {} block, and your getStatus function would be queued up again.
EDIT: Given the thread in the comments, it's also an equal likelyhood that there's a race condition going on between the two blocks of Ajax code. (just putting this here for the benefit of readers). END EDIT
What you probably want, in addition to resolving the parsing, however, is to use setInterval(), with only one timer, instead of a startTime and continueTime timer. setTimeout executes only once, whereas setInterval repeats every x milliseconds, so you'd need only one. To cancel a setInterval, use clearInterval.

Categories