Can't cancel set.interval - javascript

Checking for internet connection with the following code...
var checkstatus = 0
function checkConnection()
{
$.ajax({
url: "https://path/to/a/file.html",
data: { method: 'checkConnection'},
dataType: "html",
success: function(html)
{
clearInterval(checkstatus);
console.log('connection available');
return;
}
},
error: function(XMLHttpRequest, textStatus, errorThrown){
console.log('retrying');
checkstatus = setInterval(function(){checkConnection()},10000);
}
});
}
The line clearInterval(checkstatus); does not work as the script continues checking every 10 seconds, why is this?

HTTP request is made
Error response comes back
Interval 1 is created calling checkConnection every 10 seconds
HTTP request is made
Error response comes back
Interval 2 is created calling checkConnection every 10 seconds
HTTP request is made
Success response comes back
Interval 2 is cancelled
… but interval 1 is still running.
Don't start the interval inside the error response. Either do it as the means by which you start the very first run of checkConnection or use setTimeout instead.
setTimeout is probably better as it will avoid race conditions in which the request takes more than 10 seconds to get a response.

setInterval sets a callback to run every X seconds, and returns the ID of that callback. You're setting an additional callback to run every time your error callback happens, overwriting the previous interval's ID, but not cancelling it. When you finally do cancel an internval, it's only the last one you created.
Your error callback needs to test that setInterval hasn't already been called:
if (checkstatus == 0)
checkstatus = setInterval(function(){checkConnection()},10000);

I think it is easier if you would use setTimeout instead of the setInterval and you don't need to use the clear it then.

Related

Why my setInterval function doesn't stop

I need to write a setInterval function in javascript. Thi is the code:
var myTimer=setInterval(function(){
var time=0;
$.ajax({
url:'...'
type: "POST",
dataType:"",
success: function (response) {
if(response=="true" || time>=10000){
clearInterval(myTimer);
}
time=time+1000;
},
error: function () {
alert("FAIL");
}
});
},1000);
I don't know why It doesn't stop in clearInterval. Anyone can help me?
You've claimed that the code does "come in the 'if'", so I assume the clearInterval call is actually being made.
Given that, the most likely explanation is that the interval is being cleared (after all, select isn't broken), but before the first "true" response, you've already made more than one ajax call, and the other ones you're seeing are ones scheduled before the interval was cleared.
E.g., your code runs and:
Fires off ajax call #1, which takes more than a second to complete
Fires off ajax call #2
Ajax call #1 completes but isn't "true"
Fires off ajax call #3
Ajax call #2 completes and is "true", clearing the interval
Ajax call #3 completes
Mixing two separate asynchronous intervals (one via setInterval and one via ajax) is asking for trouble.
If the goal is to make the request once a second and stop when you get back "true", I would have the success handler schedule the next call, e.g.:
(function() {
var time = 0;
var started = 0;
start();
function start() {
started = Date.now();
$.ajax({
url: '...'
type: "POST",
dataType: "",
success: function(response) {
if (response != "true") {
// Schedule the next call to occur one second after we
// started the previous call; or almost immediately if
// the call took more than a second to complete
setTimeout(start, Math.max(0, 1000 - (Date.now() - started)));
}
time = time + 1000;
},
error: function() {
alert("FAIL");
}
});
}
})();
Let me illustrate the expected and the actual scenarios to make things clearer.
Scenario #1
The image below shows the case where all your ajax requests complete before one second. You will notice that ajax callback success (or error) functions will execute only before clearInterval (which is what you always expect).
Scenario #2
When some of your ajax requests take more than one second (which is probably what happens), then your ajax callbacks can fire before / after / before-and-after the clearInterval, which makes you feel that your setInterval doesn't stop.
Note that your time variable is useless because it's a function-scoped variable that you initialize to 0 every function call. And even if it's a global variable, it'll only clear the interval in the 11th success function callback, and nothing guarantees how long these 11 successful requests will take.
Solution
As T.J. Crowder suggested, it's better to schedule the next ajax call in the success callback of the previous one, which guarantees that your ajax requests fire sequentially (only one at a time).
Note: Because you edited your question after his answer, then you'll also need to edit the if condition like this:
success: function(response) {
if (response != "true" && time < 10000) {
setTimeout(start, Math.max(0, 1000 - (Date.now() - started)));
}
}

jQuery .ajax or .post taking too long message [duplicate]

This question already has an answer here:
Run function if jQuery.ajax waiting for respond long enough
(1 answer)
Closed 8 years ago.
I know about the timeout setting for the ajax call. But what i'm wondering is, is there a way to display a message to the user if an ajax call is still processing but taking longer than x seconds.
E.g.
During an ajax call, if it takes longer than 10 secs tell the user, "call taking longer than expected"
I'd say your best bet is to use window.setTimeout for however long you want to wait for before showing your notification, and then add a window.clearTimeout line to your success callback in your $.ajax() call:
var loadingTimeout = window.setTimeout(function() {
// show your warning here
alert('Still loading :P');
}, 10000); // 10000ms = 10sec
$.ajax({
url: 'http://your/url/here',
dataType: 'json',
type: 'GET',
success: function(r) {
window.clearTimeout(loadingTimeout);
// your results logic here
}
})
Sure, just setTimeout() yourself another function that checks some global variable that gets set by the ajax completion callback. In that function, if the ajax call is still outstanding, show a message.

Delay Execution Of Script Jquery (or SetTimeOut) BUT when out of scope

I've read some answers on this problem, but I'm not sure what to do in my case.
I have a function where the idea is it will keep attempting to connect via AJAX, and if it fails it will keep trying again every 5 seconds to submit information. This is important for a web app I'm developing where the users are offline 50% of the time and online 50% of the time.
The issue is in my current setup, I want to call setTimeOut to delay the execution of the function, but I think because I'm inside another function it has no idea about the location of startAjaxSubmitLoop() function? But when I run my code and check in console, I see millions of connections to my server one after another without a delay. It's as if the setTimeout() function delay properties was not working at all but it was still running the function?
Any ideas what I'm doing wrong?
function startAjaxSubmitLoop(id,tech_id){
//TODO: Make POST instead of GET because of pictures.
var request = $.ajax({
url: "script.php",
type: "GET",
data: { }
});
//If Successfully Sent & Got Response.
request.done(function( msg ) {
//Sometimes because of weak connections response may send, but the message it worked might not come back.
//Keep sending until for sure SUCCESS message from server comes back.
//TODO: Make sure server edits existing entries incase of double sends. This is good in case they decide to edit anyways.
$( "#log" ).html( msg );
});
//If Failed...
request.fail(function( jqXHR, textStatus ) {
//Color the window the errorColor
//alert( "Request failed: " + textStatus );
setTimeout(startAjaxSubmitLoop(id,tech_id),5000);
console.log('test');
});
}
You're calling setTimeout incorrectly. You're calling your startAjaxSubmitLoop immediately on the setTimout line and passing the result to setTimeout instead of your function. Modern setTimeout implementations (es5) let you pass args to setTimeout as below:
Instead of:
setTimeout(startAjaxSubmitLoop(id,tech_id),5000);
Use:
setTimeout(startAjaxSubmitLoop, 5000, id, tech_id); //call startAjaxSubmitLoop in 5000ms with id and tech_id
The standard way of doing this to support older browsers where setTimeout doesnt take params is to just wrap your function startAjaxSubmitLoop
setTimeout(function(){startAjaxSubmitLoop(id, tech_id)}, 5000); //equivalent to above
two ways to do this:
1) with a callback function:
setTimeout( function(){startAjaxSubmitLoop(id,tech_id);},5000);
2) with parameters listed after the function name (no parentheses) and timeout period:
setTimeout(startAjaxSubmitLoop,5000, id, tech_id);

time an ajax request

Is there any way to time how long a jquery ajax request has been going on? sometimes searches take too long and it would be nice to add a jquery abort() button if the search takes over, say, 5 seconds. Any way I can do this!
On the other end of the ajax request is a php file that makes a postgresql request.
Much thanks for any ideas!
Take a look at the timeout option (http://api.jquery.com/jQuery.ajax/). You can set it on a particular call, or globally with $.ajaxSetup().
To have the abort button appear after 5 seconds, add a setTimeout function after your call to send. Once the AJAX command is complete, you can add code to clear the timeout and remove the abort button if it exists.
var timeOutID = 0;
$.ajax({
url: 'ajax/test.html',
success: function(data) {
clearTimeOut(timeOutID);
// Remove the abort button if it exists.
}
});
timeOutID = setTimeout(function() {
// Add the abort button here.
}, 5000);
This way the abort button will never appear if AJAX returns quick enough.
Usually, I'll set a timeout once the request is sent that will trigger after 10 seconds or so and then fallback on something else to make sure it still happens (for example, form submission).
So set a variable to false, var failed = false; and do the request
At the same time that the request starts, set a timeout:
setTimeout(function() {
failed = true;
$("#form").submit();
return false;
}, 10000);
In the return function of the ajax call, check to see if the failed variable has been set to true, and if it has, don't actually do whatever it was originally trying, otherwise it could mess something up, or confuse the user if something else is happening (since these things usually happen on slower internet connections, if the next step appears while a new page is loading, they might try to interact and then the page will change).
$.post("ajaxcall.php", {'etc': "etc"},
function(returned) {
if (failed != true) {
//do whatever with returned variable
}
});
var timer = 0,
XHR = $.ajax({
url: 'ajax/mypage.html',
beforeSend: function() {
timer=setTimeout(showAbort, 5000);
}
});
function showAbort() {
$('<input type="button" value="Abort" id="abort_button"/>').appendTo('#some_parent');
$('#abort_button').on('click', function() {
XHR.abort(); //abort the Ajax call
});
}
XHR.always(function() { //fires on both fail and done
clearTimeout(timer);
if ($('#abort_button').length) {
$('#abort_button').remove(); //remove button if exists
}
});

jQuery: delay interval of ajax function till previous run is completed

I've set up an AJAX page refresh with setInterval.
From time to time, the server is so slow that a new request is initiated before the previous one has completed.
How can I prevent that?
Use a timeout value that is shorter than your refresh interval. When the request times out, it will call the error handler so you'll need to differentiate between time out errors and other types of errors in the handler.
$.ajax({
type: "POST",
url: "some.php",
data: "name=John&location=Boston",
timeout: 5000, /* ms or 5s */
success: function(msg){
alert( "Data Saved: " + msg );
}
});
Docs at jquery.com. Example above from same source, but with added timeout value.
Use setTimeout instead, initiate another setTimeout only after receiving the result of the AJAX request. That way a refresh only happens after the specified period since the last refresh.
Instead of using a fixed, hard coded interval: Trigger the next refresh as the last step of handling the current one, e.g. in the "Success" (or "Complete") event callbacks.
You could add a variable that keeps track of the time the current request was sent, so that you can calculate a dynamic delay:
take current time T1
send asynchronous request
other stuff happens...
asynchronous request returns, callback executes
subtract T1 from current time
if result < your desired request interval, set delay value > 0
if result >= your desired request interval, set delay value = 0
call setTimeout with the delay value, initiating the next cycle
What I can tell you is, use a flag in your code.
Like (not what I actually recommend just a simple example)
var isWorking = false;
function doRequest(){
if(isWorking) return;
isWorking = true;
$.ajax({
...,
success: workWithResponse
});
}
function workWithResponse(){
/* doAnythingelse */
isWorking = false;
}
setInterval(doRequest,1000);
Something like that, its primitive but you will avoid race conditions.
Regards.

Categories

Resources