Javascript setInterval - rate or delay? - javascript

Does the Javascript setInterval method wait (at least) the specified interval between two executions of the specific code, or does it wait that interval in between finishing the previous execution and the beginning of the next execution?
(or, when comparing to Java's ScheduledExecutorService methods - is setInterval similar to scheduleAtFixedRate() or rather scheduleWithFixedDelay()?)

If you call setInterval with 1000 milliseconds interval and callback code takes 100 milliseconds to run, next callback will be executed after 900 milliseconds.
If callback takes 1050 milliseconds, the next one will fire up immediately after the first one finishes (with 50 milliseconds delay). This delay will keep accumulating.
So in Java world this is similar to scheduleAtFixedRate(). If you need scheduleWithFixedDelay() behaviour, you must use setTimeout() and reschedule callback each time it finishes:
function callback() {
//long running code
setTimeout(callback, 1000);
}
setTimeout(callback, 1000);
The code above will wait exactly 1000 milliseconds after callback() finished before starting it again, no matter how long it took to run.

This answer includes help from jfriend00's comment below.
Javascript is single threaded and so the same function can not run twice at the same time. However the setInterval delay does not take into account how long it takes to run the function.
For example, say your setInterval function takes 500 milliseconds to run, and your delay is 1000 milliseconds. This would lead to a 500 millisecond delay before the function starts again.

As you can see in this jsFiddle test case, setInterval tries to keep the interval on time regardless of how long the code that runs on the interval takes as long as that code takes less time than the interval is set for. So, if you have an interval set for 5 seconds and the code that runs on each interval takes 200ms, each interval should still be 5 seconds apart (or as close as a single threaded javascript engine can make it to 5 seconds).
If, on the other hand, the code you run on each interval takes long than the interval time itself to execute, because javascript is single threaded, the following interval will not start on time and will be delayed because of the time overrun of the first interval's code.
Both of these cases can be seen in this working test case by adjusting the delay time.
Working test case here: http://jsfiddle.net/jfriend00/kGQsQ/

Related

Recursive function call with setTimeout limited to ~200 calls per second, why?

This code recursively calls the same function with a setTimeout of 1 millisecond, which in theory should call the function 1000 times per second. However, it's only called about 200 times per second:
This behavior happens on different machines and different browsers, I checked if it's has something to do with the maximum call stack, but this limit is actually way higher than 200 on any browser.
const info = document.querySelector("#info");
let start = performance.now();
let iterations = 0;
function run() {
if (performance.now() - start > 1000) {
info.innerText = `${iterations} function calls per second`;
start = performance.now();
iterations = 0;
}
iterations++;
setTimeout(run, 1);
}
run();
<div id="info"></div>
There’s a limitation of how often nested timers can run. The HTML5 standard says: 11: "If nesting level is greater than 5, and timeout is less than 4, then set timeout to 4."
This is true only for client-side engines (browsers). In Node.JS this limitation does not exist
HTML Standard Timers Section
Very similar example from javascript.info
The delay argument passed to setTimeout and setInterval is not a guaranteed amount of time. It's the minimum amount of time you could expect to wait before the callback function is executed. It doesn't matter how much of a delay you've asked for, if the JavaScript call stack is busy, then anything in the event queue will have to wait.
Also, there is an absolute minimum amount of time you could reasonably expect a callback to be called after which is dependent on the internals of the client.
From the HTML5 Spec:
This API does not guarantee that timers will run exactly on schedule.
Delays due to CPU load, other tasks, etc, are to be expected.
I once read somewhere that it was around 16ms so setting a delay of anything less than that shouldn't really change the timings at all.

Why the fiddle is not working and there is a time lag behind in following case?

My fiddle link is as follows:http://jsfiddle.net/FvYyS/2/
The function call is as follows:
load_timer('0', '6', '9', 0, '0', '', '0');
Actually my issue is the fiddle is not working. The expected behaviour of this code is the timer should decrease second by second and ultimately reaches to zero(i.e. for example the timer should start at 00:06:09 and end at 00:00:00). But it's not working here in the fiddle. The code is working properly in my application but don't know why this code is not working in fiddle. Also one more issue I noticed in my application is the timer is lagging sometime behind. Can anyone please help me in this regard? If you need any further information I'll provide you the same. Thanks in advance.
Your code has the following structure :
var counter = delay;
function loop() {
counter--;
displayTime(delay, counter);
if (counter > 0) {
setTimeout( loop, 1000 );
}
}
2 things :
displayTime() execution takes time : for example, if it takes 0.2 seconds to complete, the loop will be executed every 1.2 seconds (instead of every second)
setTimeout( ..., 1000 ) means "Please dear javascript runtime, can you run my code in 1 second ? If you have other stuff to do, it is ok for me to wait more."
You have the guarantee that there will be at least 1 second between the setTimeout call and your loop excution, but the delay can be longer.
If you want to avoid the time drift, check for the real time on each iteration :
var start = Date.now();
function loop() {
var now = Date.now();
var elapsedTime = now - start; //elapsed time in milliseconds
displayTime(delay, elapsedTime);
if (elapsedTime < delay) {
setTimeout(loop, 1000);
}
}
you have not included the jquery library in your fiddle
See UPDATED FIDDLE
There are several problems with your approach:
Since you do the setTimeout after doing some work, the time it takes for your work to be done will delay the next iterations. You could fix this by moving the setTimeout call to be the first executed and then do the work.
Using setTimeout(f, timeout) guarantees that the f function will be executed at least timeout miliseconds after the setTimeout call. So if for example the browser is busy for 1 second when the call to f should be executed, the call to f is delayed by 1 second. Furthermore, the next call to setTimeout is delayed by that second, so everything coming after that will incur your delay.
A better fix would be to use setInterval which is designed with repeating a task every n miliseconds and alleviates the recurrent delay problem.
Finally, the best solution to the problem is to use Date to determine the start of your counter and show the exact time elapsed by substracting the original time from the current time.

How is setInterval Interval managed?

If I use the setInterval function to call an asynchronous JavaScript function each X seconds will the interval wait X seconds after the previous execution is finished or X seconds after the previous execution is called? E.g. if I display a timeline of the calls is it:
0 sec : setInterval(funcX, 10000)
10 sec : funcX - takes 3 seconds to execute
20 sec : funcX
or
0 sec : setInterval(funcX, 10000)
10 sec : funcX - takes 3 seconds to execute
23 sec : funcX
Taken from Mozilla documentation:
Calls a function or executes a code snippet repeatedly, with a fixed
time delay between each call to that function.
Therefore it's every X seconds. But if the function takes longer than X seconds to execute, then the thread will be locked and will execute when it's free.
For more information on JavaScript timings I recommend John Resig's article How JavaScript Timers Work.
If you wish for it to be X seconds after the function has executed, use setTimeout() and call this at the end of your function:
runFunc();
function runFunc(){
//code here....
setTimeout(runFunc, 3000);
}
This will cause infinite recursion, emulating setInterval(), but only starting the X second delay once the current function has finished executing.
If the function actually takes 3 seconds to execute, you have serious problems.
This is not particularly relevant to you because you are using Ajax, and the actual Ajax call should be practically instantaneous.
If you want the Ajax call to complete before the interval continues again, setInterval is undesirable. Use setTimeout instead.
function atTime() {
ajax().done(function () { setTimeout(atTime, 10000); });
}
atTime();

Help chosing between settimeout and setinterval

UPDATE 2:
OK, looks like it runs the first time after a minute. How do I get it to run onload, then every minute after that?
UPDATE 1:
I've tried: var interval = setInterval(get_reported_incidents, 60000); but nothing happens. in get_reported_incidents(); I just have an alert("hello");.
ORIGINAL QUESTION:
I want to run a function every minute:
get_reported_incidents();
But I am not sure which method is best for this task;
settimeout or setinterval
It's totally personal preference. setInterval has some odd edge cases around what happens when the previous interval's code hasn't finished running before the next interval is due to start (not a problem if your interval is every minute; intervals every second, which one sometimes wants, get a bit tricky).
I tend to prefer chained setTimeout calls (where each schedules the next) because they can't run away with you — your code always has to explicitly say "Okay, and call me back again next time." But properly-written code should work with either.
Chained setTimeout calls are also more well-suited to asynchronous operations, like for instance polling something via ajax, because you don't schedule the next timeout until the ajax operation completes. Using setInterval, because the ajax calls are asynchronous, you could end up overlapping them.
Using setinterval would be the more natural choise. If you use setTimeout, you have to start a new timeout from the event handler.
window.setInterval(get_reported_incidents, 60*1000);
setTimeout runs a command once after a period of time. setInterval runs a command every time interval.
So, to run get_reported_incidents every minute use setInterval.
var interval = setInterval(get_reported_incidents, 60000);
setinterval executes a function at a given interval. settimeout executes a function after a specified wait time, and then exits.
If you are attempting to do a cron-like execution every minute, you will want to use setinterval.
Please see http://javascript.about.com/library/blstvsi.htm for a comparison.
use setTimeout recursively. See here for more information on why setInterval is a poor choice.
function timeout (){
get_reported_incidents();
setTimeout(timeout, 1000 * 60);
}
timeout(); // start
Strictly speaking, setInterval() was designed for repeating events and setTimeout() for one-shot events.
However you will tend to find that with setTimeout() time will "creep" gradually. I've not tried this at 1 minute intervals, but with a 1 second timer I found it happened quite a lot. A clock showing the current time (to the nearest millisecond) would show a steady increase in the millisecond value of "now".
See http://jsfiddle.net/alnitak/LJCJU/ and tweak the interval to see what I mean!
So, for greatest accuracy, I do this:
var timerHandler = function() {
var interval = 60000;
// do some stuff
...
var now = new Date();
var delay = interval - (now % interval);
setTimeout(timerHandler, delay);
};
This is ideal if you want the timer events to be started in sync with the clock on your system, rather than at some unspecified time "roughly every minute".
obviously setinterval might be easier to maintain in your case
get_reported_incidents(); //first call
var interval = setInterval(get_reported_incidents, 60000);
vs
var interval;
function timeout (){
get_reported_incidents();
interval=setTimeout(timeout, 60000);
}
timeout();

javascript setInterval

a question. If i use setInterval in this manner:
setInterval('doSome();',60000);
am i safe that the doSome() function is triggered every 60 seconds, even if I change the tab in a browser?
Passing a string to setInterval is fine, and is one of two ways to use setInterval, the other is passing a function pointer. It is not wrong in any way like the other answers state, but it is not as efficient (as the code must be reparsed) nor is it necessary for your purpose. Both
setInterval('doSome();', 60000); // this runs doSome from the global scope
// in the global scope
and
setInterval(doSome, 60000); // this runs doSome from the local scope
// in the global scope
are correct, though they have a slightly different meaning. If doSome is local to some non-global scope, calling the latter from within the same scope will run the local doSome at 60000ms intervals. Calling the former code will always look for doSome in the global scope, and will fail if there is no doSome function in the global scope.
The function will reliably be triggered, regardless of tab focus, at intervals of at least 60000ms, but usually slightly more due to overheads and delays.
All browsers clamp the interval value to at least a certain value to avoid intervals being too frequent (I think it's a minimum of 10ms or 4ms or something, I can't exactly remember).
Note that some browsers (the upcoming Firefox 5 is one, but there are probably others that I don't know of) further clamp setInterval drastically to e.g. 1000ms if the tab is not focused. (Reference)
No, the interval cannot execute until the event loop is cleared, so if you do for instance setInterval(func, 1000); for(;;) then the interval will never run. If other browsers tabs run in the same thread (as they do everywhere(?) except for in chrome, then the same applies if those tabs clog the event loop.)
But for an interval as large as 60000 it is at least very likely that the func will be called in reasonable time. But no guarantees.
If the tab with the setInterval() function remains open, then yes the function will be executed every 60 seconds, even if you switch to or open other tabs.
Yeah it works on an example I just created.
http://jsfiddle.net/5BAkx/
Yes, the browser's focus is irrelevant.
However, you should not use a string argument to setInterval. Use a reference to the function instead:
setInterval(doSome, 60000);
No, you are not guaranteed exact time safety. JS is event based (and single-threeaded) so the event won't fire at the exact right moment, especially not if you have other code running at the same time on your page.
The event will fire in the neighbourhood of the set time value, but not on the exact millisecond. The error may be tens of milliseconds even if no other event is running at the time. This may be an issue if for example you have a long-running process where the timing is important. If you do, you'll need to synchronize with a clock once in a while.
Yes it will be called as long as the page is open, regardless the tab is switched or even the browser is minimized.
However make sure you pass the function not a string to setInterval
it should be >
setInterval(doSome, 60000)
About "exact time safety": The following code starts UpdateAll at intervals of RefreshInterval milliseconds, with adjustment each second so that one start occurs at each second at the start of the second. There will be a slight delay for the finite speed of the computer, but errors will not accumulate.
function StartAtEachSecond ()
{
var OneSecond = 1000; // milliseconds
var MinInteral = 50; // milliseconds, estimated safe interval
var StartTime = OneSecond - (new Date ()).getMilliseconds (); // Time until next second starts.
if (StartTime < MinInteral) StartTime += OneSecond
window.setTimeout (StartAtEachSecond, StartTime + MinInteral); // To set up the second after the next.
for (var Delay = 0.0; Delay < OneSecond - MinInteral; Delay += RefreshInterval)
{
window.setTimeout (UpdateAll, StartTime + Delay); // Runs during the next second.
}
}

Categories