In my application in a particular page I use an AJAX function call continuously like below,
<script type="text/javascript">
$(document).ready(function(){
setInterval(function() {
$.ajax({
url:'clmcontrol_livematchupdate',
type:'post',
dataType: 'json',
success: function(data) {
$('#lblbattingteam').html(data.battingnow);
$('#lblscore').html(data.score);
$('#lblwickets').html(data.wickets);
$('#lblovers').html(data.overs);
$('#lblballs').html(data.balls);
$('#lblextras').html(data.extras);
$('#lblrr').html(data.runrate);
$('#lblbowlingteam').html(data.bowlingnow);
$('#lblbowler').html(data.currentbowler);
$('#lblbowlerovers').html(data.bowlerovers);
$('#lblbowlerballs').html(data.bowlerballs);
$('#lblrunsgiven').html(data.runsgiven);
$('#lblextrasgiven').html(data.extrasgiven);
$('#lblwicketstaken').html(data.wicketstaken);
$('#lblecon').html(data.econ);
}
});
}, 4000);
});
</script>
Any how at the first attempts the application ran well and the values got updated as I expected, but after few attempts more the values struggled to update and going further updates were not happening. Is it because the function slows down the system due to continuous ajax calls?
It's better not to use setInterval() because If the first request hasn't completed and start another one, you could end up in a situation where you have multiple requests that consume shared resources and starve each other. You can avoid this problem by waiting to schedule the next request until the last one has completed.
Just Try:
(function ajaxInterval() {
$.ajax({
url:'clmcontrol_livematchupdate',
type:'post',
dataType: 'json',
success: function(data) {
$('#lblbattingteam').html(data.battingnow);
$('#lblscore').html(data.score);
$('#lblwickets').html(data.wickets);
$('#lblovers').html(data.overs);
$('#lblballs').html(data.balls);
$('#lblextras').html(data.extras);
$('#lblrr').html(data.runrate);
$('#lblbowlingteam').html(data.bowlingnow);
$('#lblbowler').html(data.currentbowler);
$('#lblbowlerovers').html(data.bowlerovers);
$('#lblbowlerballs').html(data.bowlerballs);
$('#lblrunsgiven').html(data.runsgiven);
$('#lblextrasgiven').html(data.extrasgiven);
$('#lblwicketstaken').html(data.wicketstaken);
$('#lblecon').html(data.econ);
},
complete: function() {
// Schedule the next request when the current one has been completed
setTimeout(ajaxInterval, 4000);
}
});
})();
There is a potential issue here that would be obvious if you checked your network calls from a debugger. Due to the non blocking async behavior of the ajax call you have the potential to be making simultaneous ajax calls. Depending on your browser you are only allowed to make so many calls at the same time so they will queue up. In these circumstances there are also no guarantees of execution order.
In your situation I would set async: false in the ajax options. You are already gaining non interface blocking behavior by executing in the setInterval callback. Since setInterval just applies a timer in between method calls you will never have more than one ajax call operating at a given time(which is a likely culprit of your issue).
Related
I have written a simple web page where I would like to be able to execute concurrent ajax requests. I know that I can do concurrent ajax requests in jquery using .when() but that's not exactly my case. I have a function like the following:
function getData(tt, tf) {
$.ajax({
url : "/extpage.php",
type : "POST",
async: true,
data : {
testt : tt,
testf : tf
}
})
.done(function (toolbox) {
alert(data);
});
}
This function is called from a button inside the webpage and I need to be able to let the user call this function anytime he wants (I'm aware about the maximum number of the ajax requests that a browser can support) without waiting the previous ajax request to be finished first and then execute the next one. I want every call to be processed in parallel. Any clues on how I can obtain that ?
That's how AJAX works inherently. Each call you perform is run independent of any other browser activity (including, generally, other AJAX calls).
Given the function you have, if I call getData() ten times in a row, it will initiate ten independent HTTP requests. If they're not running concurrently it is possible that the server simply won't answer more than one request at a time, and of course you can't do anything about that.
I think you may need to revise your question.
This function is called from a button inside the webpage and I need to
be able to let the user call this function anytime he want
This is the default AJAX behaviour. AJAX calls are ansychronous.
async: true
is redundant, true is the default value for async.
Your code should do what you are asking in this question, if you are still experiencing a problem the issue may be elsewhere.
As one last note:
$.when()
is used to queue otherwise concurrent/async tasks, the opposite of what you suggested in the OP.
Consider I have multiple (sometimes more than 12) ajax calls that are calling every 2 seconds or more. Data gathered through the calls are set to the UI contained elements (Like progress bars). After all I have delay on SCROLL while timers working . This delay is natural, But How can I handle it?
NOTE: Calls Destinations are services that provides data with the minimum spent time. The point that makes the scroll sad, is using multiple setTimeout() and setInterval() methods. To get more familiar with my work, See the below code:
function FillData(accessUrl, name) {
var add = accessUrl;
$.support.cors = true;
if (add) {
$.ajax({
type: 'GET',
url: accessUrl,
crossDomain: true,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (data) {
Update(name, data);
},
error: function (xhr, status, error) {
LogResponseErrors(status , error, name);
}
});
setTimeout(function () { FillData(accessUrl, name); }, interval);
//Consider that the method calls with different parameters one time and it will run automatically with setTimeout
}
else {
freezeFrame(name);
}
}
Used Tags explains what I used.
Any useful answer will be appreciated
From what I understand in your question. You have delay when you're handling your ajax responses and you need to remove the delay.
Javascript is single-threaded. Therefore, if there is a function that takes long time to complete, it could dominate the thread and cause the UI not responding. To deal with this, you have 2 options:
Optimize your code so that the function does not take long.
Use setTimeout to break your function into smaller pieces. For example: if your function is executing a loop of 100 items, you could break it to execute 10 times with 10 items each.
Update: (based on updated question):
It seems that the loop never stops when you use setTimeout like this. Should have something like:
counter++;
if (counter <= 12)
setTimeout(function () { FillData(accessUrl, name); }, interval);
Due to timing problem between ajax and your setTimeout, at some points, there are a lot of events (escalated) waiting in the queue to be executed and cause performance problem. Try putting your setTimeout inside your success or complete function
I had a weird experience.
On the success of the ajax call I did loads of computation and processing on the DOM, everything was as smooth as it can be.
Next I moved the whole code written in the success to a separate javascript function which was in turn invoked on the success part of the ajax.
Now I see a lag of 1-2 seconds in execution of the function. Is it possible that inline code is faster than a function call?
EDIT
The sample code :
$.ajax({
url: '/apps/project/controller/load_data',
method: 'get',
dataType: "json",
data: {},
success: function(data) {
//Parse JSON (Huge Data) and insert into DOM
}});
The second approach I did
$.ajax({
url: '/apps/project/controller/load_data',
method: 'get',
dataType: "json",
data: {},
success: function(data) {
populate_timeline(data)
}});
function populate_timeline(json){
//Parse JSON (Huge Data) and insert into DOM
}
One suggestion would be to not compound your problems by using an anonymous pass through. You should simply be able to do success: populate_timeline as functions are first order objects in JavaScript. You may have to ensure that populate_timeline is declared before it is referenced in the ajax, I don't know how all your code is laid out or called.
I was optimizing a script recently and found that in-lining a single function call really had very little effect on performance. That was code that performed some canvas animations with a pretty short setInterval time so the function call was being made many many times a second.
Have you gone back and made sure that moving the previously in-lined code to its own function is the only thing you've done? It's easy to make other changes without thinking about it. Also if you are running this code on your local machine for development purposes, ensure it's not simply the ajax call being slower rather than the function call. Maybe you have some other CPU heavy process running now that wasn't running earlier and is slowing the ajax response?
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.
I have a function called:
function callAjax(url, data) {
$.ajax(
{
url: url, // same domain
data: data,
cache: false,
async: false, // use sync results
beforeSend: function() {
// show loading indicator
},
success: function() {
// remove loading indicator
}
}
);
}
In the code, I call "callAjax" X number of times and I want to update the data synchronously. It is done as expected, but one problem: the loading item doesn't show in beforeSend function. If I turn async to true, it works but the updates aren't synchronously done.
I've tried several things with no success. I tried putting the loading indicator before the ajax call like this:
function callAjax(url, data) {
// show loading div
$.ajax(
{
// same as above
}
);
}
But for some reason it doesn't want to show the loading indicator. I notice a strange behavior when I put an "alert" in the beforeSend and the loading indicator appears in that case, but I rather not pop up a message box.
Got any ideas?
Making a synchronous call like that is like putting up an "alert()" box. Some browsers stop what they're doing, completely, until the HTTP response is received.
Thus in your code, after your call to the "$.ajax()" function begins, nothing happens until the response is received, and the next thing as far as your code goes will be the "success" handler.
Generally, unless you're really confident in your server, it's a much better idea to use asynchronous calls. When you do it that way, the browser immediately returns to its work and simply listens in the background for the HTTP response. When the response arrives, your success handler will be invoked.
When you do the blocking I/O the program is halted until the the input is received, in JS words when doing a synchronous call, the program halts and browser window freezes (no painting can be done) until the response is received. In most cases doing syncronus calls and any kind of blocking I/O can be avoided. However imagine your doing a progress bar in java or any other programming language, you have to spawn a different thread to control the progress bar, I think.
One thing to try in your case, is to call the ajax call after a time delay
//loading div stuff,
//if your doing some animation here make sure to have Sufficient
//time for it. If its just a regular show then use a time delay of 100-200
setTimeout( ajaxCall, 500 );
EDIT ajaxcall in setTimeout, Example
This is what you are looking for - .ajaxStart()
It will be triggered when any ajax event starts
http://api.jquery.com/ajaxStart/
They even give a specific example similar to what you are trying to accomplish:
$("#loading").ajaxStart(function(){
$(this).show();
});
You can then use the .ajaxStop() function
$("#loading").ajaxStop(function(){
$(this).hide();
});