How can you stop polling due to a timeout? - javascript

So I'm polling something pretty standard
(function poll(){
$.ajax({ ... })
});
... and it works well. But now, I want to be able to continue polling every couple seconds and then if I don't get a response after two minutes, stop polling and raise an error.
How do I do the timeout?

How about something like this. Init, track, and reset the polling within the ajax promises.
var pollingTimer = null, // stores reference to the current timer id
firstTimeoutResponse = null; // stores the start of what might be a series of timeout responses
function poll(){
$.ajax({
// your options here...
}).done(function() {
// reset the "timeout" timer
firstTimeoutResponse = null;
}).fail(function(jqXHR, textStatus) {
// if the failure wasn't a timeout, short-circuit,
// but only after resetting the timeout timestamp
if (textStatus !== 'timeout') {
firstTimeoutResponse = null;
return;
}
// if it was a timeout failure, and the first one (!), init the timeout count
if (firstTimeoutResponse = null) {
firstTimeoutResponse = (new Date).getTime();
}
}).always(function() {
// if 2 min have passed and we haven't gotten a good response, stop polling/chort-circuit
if ((new Date).getTime() - firstTimeoutResponse > 120000) { // 120000ms = 2min
window.clearTimeout(pollingTimer);
return;
}
// queue the next ajax call
pollingTimer = window.setTimeout(poll, 3000); // poll every 3s
});
}
// kick things off!
poll();

Related

AJAX request get's called twice because of an interval

I've a problem with my interval function. This is my function:
let data = {
action: "verify_status",
};
let interval = setInterval( function () {
if ( new Date().getTime() - startTime > 600000 ) {
alert( "Error: Timed out!" );
clearInterval( interval );
}
jQuery.post( ajax_url, data, function () {
} ).success( function () {
clearInterval( interval );
successFunction();
} ).fail( function ( response ) {
if ( response.status === 500 ) {
clearInterval( interval );
}
} );
}, 5000 );
My problem is now the following: The interval starts an AJAX request, which now runs in parallel. This is fine as long as the request fails with HTTP 400.
But if it runs successfully, my successFunction() is called. Unfortunately the interval continues running outside. As a result my successFunction() is called twice and sometimes three times, although I interrupt the execution with clearInterval(). Does anyone have an idea how I can do this better?
If you don't want the requests to fire in parallel, then don't use an interval. Instead, use a timeout which only runs once. When the AJAX request completes, set a new timeout to trigger the next one. That's a much better way to ensure that there's no overlap.
Something like this:
setTimeout(runAjax, 5000);
function runAjax()
{
if (new Date().getTime() - startTime > 600000) {
alert( "Error: Timed out!" );
}
jQuery.post(ajax_url, data)
.success(function ()
{
successFunction();
setTimeout(runAjax, 5000);
})
.fail( function ( response ) {
setTimeout(runAjax, 5000);
});
}
You cleared the interval with the name verifyPaymentInterval on success. Try clearing the one with the name "interval" as well.

Exit setTimeout loop within AJAX GET request

I have a function that performs an AJAX GET request every 1 second to retrieve data and update a progress bar. I'm using setTimeout to accomplish this. Here is the code:
function check_progress(thread_id) {
function worker() {
$.get('ecab_run/progress/' + thread_id, function(data) {
progress = data['progress'];
status_message = data['status_message'];
if (progress < 100) {
$('.progress-bar').css('width', progress+'%').attr('aria-valuenow', progress);
$('.progress-bar')[0].innerHTML = progress+"%";
$('#status-message')[0].innerHTML = status_message
timer = setTimeout(worker, 1000);
// console.log(timer);
} else if ( progress == 100 ){
$('.progress-bar').css('width', progress+'%').attr('aria-valuenow', progress);
$('.progress-bar')[0].innerHTML = progress+"%";
}
})
return status_message;
}
worker();
}
The function is called after a successful POST as such:
$('#ecab-run-dates').submit(function(e){
e.preventDefault();
var formData = $('form').serialize();
$.ajax({
url:'',
type:'post',
data:formData,
success:function(data){
thread_id = data;
$('.progress-container').show();
check_progress(thread_id);
}
});
});
The backend returns status messages as the behind-the-scenes functions execute, and when it encounters an error, it returns Error: could not compile data or something similar.
My initial thought was to use the error message as a condition for stopping the check_progress function. I've read several answers, including this one that say to use clearTimeout, but I'm not exactly sure how to structure that in my code. Can someone help me exit the setTimeout loop when encountering an error?

jQuery ajax requests only working linear and not parallel

I would like to set up a progressbar showing the progress of a long working task which imports a large CSV-File and pass to the database. I start the import process with an initial jQuery.ajax call and setting up a timeout to get the processed lines from these file in percent.
The problem is when I start the initial ajax-call, all other ajax-calls just wait to be executed until the initial call is done.
So this is my code:
var progress = false;
var update_progress = function() {
if(progress) {
$.ajax({
url: 'index.php?do=update_progress'
},
function(json) {
// Something < 100
if(json.perc !== undefined) {
$('#progress').css('width', json.perc + '%');
}
setTimeout(update_progress, 1000);
});
}
}
var start_import = function(i) {
// Setting progress allowed
progress = true;
// start the update in 1s
setTimeout(update_progress, 1000);
// start the database-import (20-30 seconds runtime on server)
$.ajax({
url: 'index.php?do=start_import'
},
function(json) {
// Import finished, disallow progressing
progress = false;
// Finally always complete: json.perc is 100
if(json.perc !== undefined) {
$('#progress').css('width', json.perc + '%');
}
});
};
start_import();
This is a bit confusing, because I thought that each call can work itself asynchronously. What is wrong?
Regards Tim
Why do you not call setInterval() instead of setTimeout()? This is the problem! The next call of the function update_progress() will happen after the callback from the previous AJAX call returned!

Call javascript function after specific time intervals

I am writing code for JavaScript.In which I am trying to check the remote asp.net page(aspx) connection using AJAX.But also I want to check the condition that, this call will continue for 2 Minute only and with 10 sec time intervals.
not that but like that logic I am thinking,
If flag=true
if seconds < 120
setInterval("GetFeed()", 2000);
can anybody please help me for that.
Here is my code of Connection check,
var learnerUniqueID1;
var flag='true';
function fnCheckConnectivity(coursId)
{
//here will the remote page url
var url = 'http://<%=System.Web.HttpContext.Current.Request.UrlReferrer.Host+System.Web.HttpContext.Current.Request.ApplicationPath%>/TestConn.aspx';
//alert(url);
if (window.XMLHttpRequest) {
learnerUniqueID1 = new XMLHttpRequest();
}
else if (window.ActiveXObject) {
learnerUniqueID1 = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
alert("Your browser does not support XMLHTTP!");
}
learnerUniqueID1.open("POST", url, true);
learnerUniqueID1.onreadystatechange = callbackZone;
learnerUniqueID1.send(null);
}
function callbackZone()
{
if (learnerUniqueID1.readyState == 4)
{
if (learnerUniqueID1.status == 200)
{
//update the HTML DOM based on whether or not message is valid
parseMessageZone();
}
else
{
flag='false';
alert('We have detected a break in your web connection, \n please login again to continue with your session');
}
}
}
function parseMessageZone()
{
var result = learnerUniqueID1.responseText;
}
function makePayment(obj)
{
try
{
var Id = obj.attributes["rel"].value
//alert(Id);
var res=confirm('Want to Continue.');
if(res == true)
{
startRequest(Id);
//return true;
}
else
{
return false;
}
}
catch(Error)
{
}
}
function startRequest(Id)
{
var milliseconds = 10000;
currentDate = new Date();
// start request
pollRequest(milliseconds, false, currentDate, 120000,Id);
}
function pollRequest(milliseconds, finshed, date, timeout,Id)
{
if((new Date()).getTime() > date.getTime()+timeout)
{
// 2-minute timeout passed
return;
}
if(!finished){
setTimeout(function(){
if(//check backend to see if finished) //which method will go here
{
fnCheckConnectivity(coursId);
pollRequest(milliseconds, true, date, timeout,Id);
}
else{
pollRequest(milliseconds, false, date, timeout,Id)
}
}, milliseconds);
return;
}
// when code reaches here, request has finished
}
I'm not sure I understand correctly, but if you are trying to poll the status of a request you made every ten seconds, why not try something like this?
function startRequest(){
var milliseconds = 10000;
currentDate = new Date();
timeout = 120000;
// start request
pollRequest(milliseconds, false, currentDate, timeout);
}
function pollRequest(milliseconds, finshed, date, timeout){
if((new Date()).getTime() > date.getTime()+timeout){
// 2-minute timeout passed
return;
}
if(!finished){
setTimeout(function(){
if(//check backend to see if finished){
pollRequest(milliseconds, true, date, timeout);
}
else{
pollRequest(milliseconds, false, date, timeout)
}
}, milliseconds);
return;
}
// when code reaches here, request has finished
}
Please note this is a recursive function and browsers have a recursion limit. Also, regarding the 2 minute timeout, you can either set the timeout as an ajax prefilter or add a variable that is added on each recursion.
If I understand correctly to want to do a task for 2 minutes every 10 seconds.
var interval = setInterval(function(){
// do stuff
},10000); // execute every 10 seconds
setTimeout(function(){
clearInterval(interval);
},120000); // Remove interval after 2 minutes
You don't want a script running continuously on a server/client. You should look up chronjob for linux or scheduler for windows.
I didn't give you a proper solution, just an alternative. For what you seem to want to do, however, this seems like the right tool.
Instead of a push request that you're describing, in which the client user waits for a certain amount of time and then makes a request, you should use a pull request.
To do that, you can make an AJAX call to the sever, and then the sever can wait (and possibly do something else while waiting) and then return something to the user when data is ready.

JQUERY AJAX ---- Pausing for usability reasons but only when nessesary?

I have a LoadingStatus Function that has two options SHOW or HIDE.
The Show triggers to display when the JQUERY POST is made, the HIDE happens after the RESPONSE comes back.
The issue I'm having is that sometimes this happens so fast that it makes for a bad experience. What I thought about doing was putting in a JavaScript PAUSE, but if the POST takes a while to respond it will take even longer because of the PAUSE.
How can I have my SHOW HIDE function work together, to make sure at minimum the SHOW was displayed to the user for at least 1/2 second?
function saveBanner (action) {
if (action == 'show') {
// Display the AJAX Status MSG
$("#ajaxstatus").css("display","block");
$("#msg").text('Saving...');
}
else if (action == 'hide') {
$("#ajaxstatus").css("display","none");
$("#msg").text('');
}
};
Thanks
In your ajax success callback, you can put the hide command in a setTimeout() for 1500 miliseconds:
success: function(results) {
setTimeout(function(){
saveBanner("hide");
}, 1500);
}
Of course that would merely add 1.5 seconds onto however long the process itself took. Another solution would be to record the time the process started, with the Date object. Then, when the callback takes place, record that time and find the difference. If it's less than a second and a half, set the timeout for the difference.
/* untested */
var start = new Date();
success: function(results) {
var stop = new Date();
var difference = stop.getTime() - start.getTime();
difference = (difference > 1500) ? difference : 1500 ;
setTimeout(function(){
saveBanner("hide");
}, difference);
}
You can perform this math either inside your callback, or within the saveBanner() function itself, within the show portion you would set the starting time, within the hide() portion you would check the difference and set the setTimeout().
You can use setTimeout/clearTimeout to only show the status when the response takes longer than a set amount of time to load.
Edit:
Some untested code:
var t_id = 0;
function on_request_start()
{
t_id = setTimeout(show_message, 1000);
}
function on_request_completed()
{
clearTimeout(t_id);
hide_message();
}
The JQuery handlers should look something like the above. The message will not be shown if you receive a reply in less than a second.
var shownTime;
function saveBanner (action) {
if (action == 'show') {
// Display the AJAX Status MSG
$("#ajaxstatus").css("display","block");
$("#msg").text('Saving...');
shownTime = new Date().getTime();
}
else if (action == 'hide') {
var hideIt = function() {
$("#ajaxstatus").css("display","none");
$("#msg").text('');
};
var timeRemaining = new Date().getTime() - shownTime - 1500;
if (timeRemaining > 0) {
setTimeout(hideIt, timeRemaining);
else {
hideIt();
}
}
};
As of jQuery 1.5, you are able to extend the $.ajax functionality by using prefilters. I wanted a similar experience where a message was shown a minimum amount of time when an ajax call is made.
By using prefilters, I can now add a property to the ajax call named "delayedSuccess" and pass it a time in milliseconds. The time that is passed in is the minimum amount of time the ajax call will wait to call the success function. For instance, if you passed in 3000 (3 seconds) and the actual ajax call took 1.3 seconds, the success function would be delayed 1.7 seconds. If the original ajax call lasted more than 3 seconds, the success function would be called immediately.
Here is how I achieved that with an ajax prefilter.
$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
if (originalOptions.delaySuccess && $.isFunction(originalOptions.success)) {
var start, stop;
options.beforeSend = function () {
start = new Date().getTime();
if ($.isFunction(originalOptions.beforeSend))
originalOptions.beforeSend();
};
options.success = function (response) {
var that = this, args = arguments;
stop = new Date().getTime();
function applySuccess() {
originalOptions.success.apply(that, args);
}
var difference = originalOptions.delaySuccess - (stop - start);
if (difference > 0)
setTimeout(applySuccess, difference);
else
applySuccess();
};
}
});
I first check to see if the delaySuccess and success options are set. If they are, I then override the beforeSend callback in order set the start variable to the current time. I then override the success function to grab the time after the ajax call has finish and subtract the difference from the original delaySuccess time. Finally, a timeout is set to the computed time which then calls the original success function.
I found this to be a nice way to achieve this effect and it can easily be used multiple times throughout a site.

Categories

Resources