Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternative to setInterval that waits for function to complete

Currently, I'm using setInterval to run several AJAX functions that call PHP pages like so -

var intervalOne = setInterval(ajaxfunction, 1500);

This works fine on a test server with a tiny response time. However occasionally on my live server, there will be a bit of lag and the interval time will come again before the first one has finished, repeating the same call, and causing duplicate data to appear.

Is there any way to keep the same interval time, but have it wait to call the function if the first one hasn't finished yet?

Alternatively, Is there anything I can put in a readystate portion of the AJAX calls to have them trigger themselves again once they are complete?

Edit - Example of one of my ajax calls:

function Send() {
var name = document.getElementById('name').value;
var message = document.getElementById('message').value;

var xmlhttp = getXMLHttp();

xmlhttp.onreadystatechange = function() {
    if(xmlhttp.readyState == 4)
    {
        document.getElementById('message').value = "";

        if(xmlhttp.responseText != "") {
            var chat = document.getElementById('messagebox');
            chat.innerHTML = chat.innerHTML + '<div class=\"alert\">' + xmlhttp.responseText + '</div>';
            chat.scrollTop = 1000000000;
        }
    }
}

xmlhttp.open("POST","submit_message.php",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("name=" + name + "&message=" + message);

}
like image 789
Morgan Avatar asked Jun 16 '12 12:06

Morgan


Video Answer


2 Answers

The easy way is through blindly reapplying setTimeout at the end of your process:

function foo() {
  // possibly long task
  setTimeout(foo, 1500);
}
foo();

This would wait 1500ms between your processes. Like this: 300ms process, 1500ms wait, 2000ms process, 1500ms wait, 400ms process, 1500ms wait...

A bit more closely to what you want, you could reapply setTimeout at the beginning of your process. In this case, you'd get: 300ms process, 1200ms wait, 2000ms process, 0ms wait, 400ms process, 1100ms wait... The problem that happens with setInterval doesn't happen here, because this only schedules the next iteration, not all future ones. Notice also that since JS is single-threaded, an event can't interrupt itself like you could get in some other languages.

function foo() {
  setTimeout(foo, 1500);
  // possibly long task
}
foo();

And yeah, I guess it's more popular these days to make it self-executing, as you can see in some answers; but that's just aesthetics, the end effect is the same.

like image 178
Amadan Avatar answered Oct 08 '22 19:10

Amadan


You can replace setInterval() with setTimeout() being constantly rescheduled on every AJAX response:

function Send() {
    //...
    xmlhttp.onreadystatechange = function() {
        if(xmlhttp.readyState == 4) {
            setTimeout(Send, 1500);
            //...
        }
    }
}

Send();

If you don't need millisecond precision this is fine (time between calls will be 1500 ms + average response time). If you need to call the server exactly every 1500 milliseconds you can subtract response time from 1500 ms.

like image 32
Tomasz Nurkiewicz Avatar answered Oct 08 '22 18:10

Tomasz Nurkiewicz