How to Handle delays that made by multiple timeouts (containing ajax calls) - javascript

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

Related

Asynchronous JavaScript polling freezes the browser using setTimeout or setInterval

I write a polling script to receive newly created data records. I want to execute the call in every N seconds.
I tried setTimeout() and setInterval() to run the polling asynchronously, but both freeze the browser while executing the Polling() function, which is really strange for me.
I call the StarPolling() function when the page is loaded. APICall() function is a jQuery $.POST function which is working well - and async - in any other situations.
This is the code I use with setTimeout()
var pollinginterval = 5000;
function StartPolling()
{
setTimeout(Polling, pollinginterval);
}
function Polling()
{
[... some code ...]
var api_call = 'API_URL';
var api_call_parameters = {
[...]
};
APICall(api_call, api_call_parameters, function(json_response)
{
/* this is the callback belongs to the $.POST request */
[... some code ...]
setTimeout(Polling, pollinginterval);
});
}
The version I tried using setInterval() is very similar except the recursive call.
I can not use Workers or HTML5 sockets for this because cross-browser support is a must.
Is there any way to run the polling in a REAL asynchronous way, or using a new 'thread' with JavaScript without freezing the browser?
UPDATE:
This is how the APICall() operates:
function APICall(call, parameters, success_callback)
{
$.post(apibase + "" + call,parameters)
.done(function(response){
try
{
var json_response = $.parseJSON(response);
}
catch(error)
{
[...]
}
if(json_response.header.status == "OK")
{
success_callback(json_response);
}
else if(json_response.header.status == "error")
{
[...]
}
})
.fail(function(error) {
[...]
});
}
UPDATE: I am testing the polling with a normal and private browser (firefox) window at the same time to try the functionality. I just noticed, that the problem only occurs when both windows are running the polling simultaneously.
Maybe it is a firefox bug...
The OP is wanting to run Polling in such a way that it doesn't interfere with the main thread (i.e. in a background thread). The only way to do this is to use a WebWorker, which he specifically doesn't want to use.
For a bunch of interesting reading see the W3 document about event loops, but basically everything that happens in the browser is single threaded. All javascript will happen on the main thread (except for web workers). All setTimeout and setInterval do is queue a callback that will get run in the main thread after ~x seconds.
So sorry, there isn't any other way beside web workers.
You may use a long polling pattern like this :
(function Polling() {
setTimeout(function() {
$.ajax({ url: "server", success: function(response) {
//your try/catch here
}, dataType: "json", complete: Polling });
}, 5000);
})();
So the poll will attempt to finish before to restart, even if the server job is quite long...

Does AJAX function call within regular intervals would slow down the application?

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).

JS - Getting alert multiple times while long polling on success?

I was following a video tutorial on how to do long polling, and it seems I got it done, but I'm having one issue, for some reason, though I get one response from server, my alert shows up 3-6 times. I thought "success" only happens once if we got one response.
2nd question is, how can I make this javascript code cancel the ajax call every 30 seconds, and restart it? I've put in setInterval with .abort() in there while experimenting with no luck, probably wrong placement.
Thank you for the wisdom and help!
var timestamp = null;
var imp = null;
var annk = null;
function waitForMsg(){
$.ajax(
{
type: "GET",
url: "/test?timestamp=" + timestamp + "&imp=" +imp + "&annk=" +annk,
dataType : 'json',
async: true,
cache: false,
success: function(data)
{
alert("hello");
if(data.annkr > "0"){
$("#myidone").css("background-color", "#cccccc");
}else{
$("#myidone").css("background-color", "#cccccc");
}
if(data.impr > 0){
$("#myidtwo").css("background-color", "#000000");
}else{
$("#myidtwo").css("background-color", "#000000");
}
annk = data.annkr;
imp = data.impr;
timestamp = data.timestamp;
setTimeout('waitForMsg()',2000);
}
});
}
$(document).ready(function(){
waitForMsg();
});
I read stuff on Stackoverflow about readystates, but how do I make sure it's ready only once and does it after it's ready?
If the code is exactly the one you posted, there's no reason to show the alert more than 1 and then after 2s for the rescheduling.
Can you make a jsFiddle for that showing the problem?
The second question is more interesting. You can use the timeout option in the .ajax call and then, in the error handler, just reschedule the call.
My personal suggestion is to refactor your code to use the new JQuery Ajax style base on .done .fail and .always.
And that setTimeout should be written as setTimeout(waitForMsg,2000). Using the string parameter you evaluate that string instead of just calling the function and it's a performance penalty (so small that's hardly noticeable but that is ).
You might be seeing the alert multiple times due to the setTimeout() in your success function, you keep calling the waitForMsg() function. Just a guess.
To abort the request you could do something like this:
var timer = null;
function waitForMessage() {
var req = $.ajax(YOUR_CODE);
// The 30 second timeout
timer = setTimeout(function() {
req.abort();
waitForMessage();
}, 30000);
}
Or slightly better maybe:
function waitForMsg() {
$.ajax({
timeout: 30000,
error: function(err) {
if(err === 'timeout') {
waitForMsg();
}
}
})
}
Actually you should use setInterval instead of setTimeout, using this approach if your ajax call fails, you will forcelly abort the loop.
You could also, cancel or change the timeout timings depending on the usage of your service for network resource sanity.

JavaScript Library to Synchronize Events

let's say I'm doing 3 ajax calls and I want to wait for the 3 calls to finish before doing something.
Is there a library out there to synchronize multiple async events in JavaScript ? (using or not jQuery's event system)
Ex.:
var sync = new syncLib();
$('a1').click(sync.newListener());
$('a2').click(sync.newListener());
sync.wait(function(e1, e2) {
// fired when both a1 and a2 are clicked or when 10 seconds have passed
// e1 and e2 would have properties to know whether or not they timed out or not..
}, 10 /* timeout */));
I have found this one: https://github.com/Ovea/js-sync/blob/master/README.md, but timeouts are not supported. (Let's say the second ajax call takes too long, I don't want my synchronization to be hung up, I want to set a 10 secs timeout)
I know I can code something myself, but I'm just checking here (after googling for it)
Thanks!
EDIT:
Since then I found async: https://github.com/caolan/async
$.when($.ajax("/"), $.ajax("/"), $.ajax("/")).then(function () {
alert("all 3 requests complete");
});
Documentation
you can use jquery deferred object
here is a useful post http://www.erichynds.com/jquery/using-deferreds-in-jquery/
The .deferred, .when, .then solution mentioned in other answers is much more elegant, but it's also possible write your own simple solution just so you see how this can be done manually. You just set a counter for how many ajax calls you have in flight and in the success handler for each ajax calls, you decrement the counter and fire your action when the counter gets to zero.
function DoMyAjaxCalls(callbackWhenDone) {
var numAjaxCalls = 3;
// set timeout so we don't wait more than 10 seconds to fire the callback
// even if ajax calls aren't done yet
var timer = setTimeout(callbackWhenDone, 10*1000);
function checkAjaxDone() {
--numAjaxCalls;
if (numAjaxCalls == 0) {
clearTimeout(timer);
callbackWhenDone();
}
}
// first ajax call
$.ajax({
url: 'ajax/test1.html',
success: function(data) {
// write code to handle the success function
checkAjaxDone();
},
error: checkAjaxDone
});
// second ajax call
$.ajax({
url: 'ajax/test2.html',
success: function(data) {
// write code to handle the success function
checkAjaxDone();
},
error: checkAjaxDone
});
// third ajax call
$.ajax({
url: 'ajax/test3.html',
success: function(data) {
// write code to handle the success function
checkAjaxDone();
},
error: checkAjaxDone
});
}
Here you have a [library][1] based on jQuery made for that purpose.
In simple use-cases, $.when() is BEST but jcon-q-rency allows you to synchronize any asynchronous code sections.
http://www.megiddo.ch/jcon-q-rency

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