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.
Related
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
In my web application, I'm using an $.ajax() request to load data from a database and display it in the browser. During the execution of the request, I display a Loading Results ... message like this:
$.ajax({
// ...
beforeSend: function() {
$('#loading-results-message').show();
},
complete: function() {
$('#loading-results-message').hide();
}
});
This works fine. However, if there is not much data to load, the request takes only a fraction of a second. In this case, the message is only displayed for a fraction of a second as well. This animation happens so quickly that it's difficult to recognize it. Therefore, it would be great if it was possible to display the message only if the request takes a certain amount of time, i.e. some seconds at least but not only a fraction of a second. Is that possible somehow? By the way, I'm using Django on the server side, if that should matter.
Use setTimeout to establish a timer, cancel the timer when the request completes:
var desired_delay = 2000;
var message_timer = false;
$.ajax({
// ...
beforeSend: function() {
message_timer = setTimeout(function () {
$('#loading-results-message').show();
message_timer = false;
}, desired_delay);
},
complete: function() {
if (message_timer)
clearTimeout(message_timer);
message_timer = false;
$('#loading-results-message').hide();
}
});
Documentation
setTimeout on MDN - https://developer.mozilla.org/en-US/docs/DOM/window.setTimeout
clearTimeout on MDN - https://developer.mozilla.org/en-US/docs/DOM/window.clearTimeout
I am with #chris on this solution. But it might also be worth your while to look into http://api.jquery.com/jQuery.ajaxSetup/
This will make it so you won't have to write the timeout for every single request.
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
I use setInterval and sometimes it happens "too fast". Here how it looks:
setInterval(function() {
//here comes ajax functions and so on.
}, 1000);
Sometimes setInterval happens faster than all those ajax functions and it gives me two messages instead of one. What a solution to this?
It's hard to tell what you're running into, the question is a bit unclear.
setInterval is great for some things, but not for anything where you're going to be mixing other asynchronous stuff in with it. Instead, use the "rescheduling setTimeout" idiom:
setTimeout(doSomething, 1000);
function doSomething() {
$.ajax("your_url", {
success: function() {
// Do something here
// Do something else here
},
complete: function() {
// Previous run complete, schedule the next run
setTimeout(doSomething, 1000);
}
});
}
...because, after all, your ajax call may take more than a second to complete.
If that's not the problem you're having, my guess is your code looks something like this:
setInterval(function() {
$.ajax("your_url", {
success: function() {
// Do something here
}
});
// Do something else here
}, 1000);
...and you're wondering why the "Do something else here" code is running before the "Do something here" code. If so, the reason is that by default, ajax calls are asynchronous. Your call to $.ajax starts the call, but that's all; then all your other code runs before the success (or error) callbacks occur.
The fix, of course, is to not do anything else at the top level that relies on the success callback:
setInterval(function() {
$.ajax("your_url", {
success: function() {
// Do something here
// Do something else here
}
});
}, 1000);
With jQuery 1.5.x you can use the Then() for deferred object. This is a nice way to say once you are done then() do this. You can also use the When() option to have it wait for more than one ajax request to complete.
These two things are very cool and powerful.
http://api.jquery.com/deferred.then/
http://api.jquery.com/jQuery.when/
Set a flag that indicates that the ajax fetches are in process. When all of the ajax fetches complete, clear the flag. At the top of your setInterval function, return immediately if the flag is set.
It's better not to use setInterval, but to set a fresh setTimeout each time. For example:
setTimeout(function ajaxStuff() {
// here comes ajax functions and so on.
setTimeout(ajaxStuff, 1000);
}, 1000);
Of course, if the functions within are asynchronous, as AJAX requests normally are, the setTimeout call will still come too soon. You'll need to write some code that calls setTimeout when the requests are complete. $.when helps you with this, since $.ajax and other jQuery AJAX methods implement $.Deferred:
setTimeout(function ajaxStuff() {
$.when(
$.ajax({
url: 'ajax1.htm'
}),
$.ajax({
url: 'ajax2.htm'
}),
$.ajax({
url: 'ajax3.htm'
})
).done(function() {
setTimeout(ajaxStuff, 1000);
});
}, 1000);
I think the problem here is due to scope. Eventhough the method is triggered successfully.
With similar problem I have able to use this to fix:
setTimeout(function(){
load1();
}, 5000);
function load1 () {
console.log('loaddd1..');
setTimeout(load2(), 4000);
}
function load2 () {
setTimeout(function(){
console.log('end load2');
}, 4000);
had this issue and clearInterval wasn't working.
make sure setInterval is only called once by wrapping it in an if statement:
var interval;
if (typeof(interval) === 'undefined') {
interval = setInterval(actFakeData,3000);
}
also helpful for me was assigning setInterval to a variable and console.log it so you can see the value throughout your code. for me when it was speeding up it was increasing in numeric value instead of resetting until I wrapped it in this.
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.