can setInterval drift over time? - javascript

I have 2 node.js webservers. I cache data inside webservers. I sync the cache load/clear based on system time. I have done time sync of all my hosts.
Now I clear cache every 15 mins using following code:
millisTillNexthour = "Calculate millis remaining until next hour"
setTimeout(function() {
setInterval(function() {
cache.clear();
}, 60000*15);
}, millisTillNexthour);
My expectation is even if this process runs for ever, cache will be cleared every 15th minute of each hour of the day.
My question is: can setInterval drift over time?
For eg: right now it clears cache at 10:00 10:15 10:30 10:45 11:00 ......
Can it happen that instead of 10:15 system time, setInterval gets executed at 10:20 system time when it was supposed to clear cache at 10:15??
I am not sure how this works. Please shed some light. I hope I explained my question well.

I'm probably more than a bit late to the party here, but this is how I solved this particular time-slipping problem just now, using a recursively called setTimeout() function instead of using setInterval().
var interval = 5000;
var adjustedInterval = interval;
var expectedCycleTime = 0;
function runAtInterval(){
// get timestamp at very start of function call
var now = Date.now();
// log with time to show interval
console.log(new Date().toISOString().replace(/T/, ' ').replace(/Z/, '') + " runAtInterval()");
// set next expectedCycleTime and adjustedInterval
if (expectedCycleTime == 0){
expectedCycleTime = now + interval;
}
else {
adjustedInterval = interval - (now - expectedCycleTime);
expectedCycleTime += interval;
}
// function calls itself after delay of adjustedInterval
setTimeout(function () {
runAtInterval();
}, adjustedInterval);
}
On each iteration, the function checks the actual execution time against the previously calculated expected time, and then deducts the difference from 'interval' to produce 'adjustedInterval'. This difference may be positive or negative, and the results show that actual execution times tend to oscillate around the 'true' value +/- ~5ms.
Either way, if you've got a task that is executing once a minute, and you run it for an entire day, using this function you can expect that - for the entire day - every single hour will have had 60 iterations happen. You won't have that occasional hour where you only got 59 results because eventually an entire minute had slipped.

setInterval is definitely drifting (although I agree that it should not be). I'm running a Node.js server with an interval of 30 seconds. On each tick, a few async web requests are made which from beginning to end take roughly 1 second. No other user-level/application processing happens in the intervening 29 seconds.
However, I notice from my server logs that over the course of 30 minutes, a drift of 100ms occurs. Of course, the underlying operating system is not to blame for the drift and it can only be some defect of Node.js's design or implementation.

I am very disappointed to notice that there is a bug in the NodeJS implementation of setInterval. Please take a look at here:
https://github.com/nodejs/node/issues/7346#issuecomment-300432730

You can use Date() object to set specific time and then add a certain number of milliseconds to the date.

It definitly can because of how Javascript works (See Event Loop)
Javascript event loop executes the setInterval queue when other queued events are finished. These events will take some time and it will effect your setInterval function's execute time and it will eventually drift away as time passes.

setInterval should not drift in a perfect world. It might be delayed due to other things taking up system resources. If you need a more precise solution to what you have, use the clock() function to " calibrate " your nodes.

Related

setInterval is not run at exact interval

If you create a very simple program that has a setInterval with 1 second delay, and you log the times its function is called, you will notice that the interval 'drifts'.
Basically, it actually takes (1,000ms + some amount of time) between each call.
For this program, it actually takes ~1,005ms between each call.
What causes the drift?
Is it taking 5ms to requeue setInterval?
Is it the length of the time it takes to run the function? (I doubt this, but having trouble concluding.)
Why does setInterval behave this way, and not just base itself on some clock time? (e.g. if you have 1,000ms delay and you started at time 3... just check if 1,003 then 2,003 and so on has elapsed?)
Example:
const startTime = new Date().valueOf();
function printElapsedTime(startTime) {
console.log(new Date().valueOf() - startTime);
}
let intervalObj = setInterval(printElapsedTime, 1000, startTime);
Output:
1005
2010
3015
4020
So you are not sync'd to 1 second anymore. Since it drifts by about 5, after 100 runs it will be running a half second 'later' than expected.
This question discusses how to avoid this drift, but does not explain WHY this drift is happening. (As in it does not say that setInterval is recursively adding itself to the event queue after each call - which takes 3ms ... which is just a guess at the drift cause).
While no Javascript running on a standard browser claims to be real-time (as pointed out in several comments) there are steps you an take to make things not get as out of hand as it appears the example in the question does (the errors being cumulative).
Just to start with an experiment I ran this on my Windows 10 Chrome:
const startTime = new Date().valueOf();
function printElapsedTime(startTime) {
let curTime = new Date().valueOf();
console.log(curTime - startTime);
}
let intervalObj = setInterval(printElapsedTime, 1000, startTime);
<div id="show">0</div>
This gave fairly consistent error each second and around the minute time you can see there was no cumulative drift:
However, using Firefox on the same system there was cumulative drift and this can be seen as pretty significant by the one minute mark:
So the question is, can anything be done to make it a bit better across browsers?
This snippet ditches setInterval and instead uses setTimeout on each invocation:
const startTime = new Date().valueOf();
let nextExpected = startTime + 1000;
function printElapsedTime(startTime) {
let curTime = new Date().valueOf();
console.log(curTime - startTime);
let nextInterval = 1000 + nextExpected - curTime;
setTimeout(printElapsedTime, nextInterval, startTime);
nextExpected = curTime + nextInterval;
}
let intervalObj = setTimeout(printElapsedTime, 1000, startTime);
<div id="show">0</div>
On Firefox this gave:
There was no cumulative drift and the error around the one minute mark was no worse than earlier.
So, in attempt to actually answer the question:
Computers do have other duties to attend to and cannot guarantee to process a timeout function at an exact time (though the spec requires them not to process before the interval has elapsed). In the given code in particular console.log will take time, settingup a new interval (in the final example) takes time, but the laptop/phone etc will also be dealing with lots of other stuff at the same time, housekeeping in the background, listening for interrupts etc etc.
Different browsers seem to treat setInterval differently - the spec doesn't seem to say what if anything they should do about cumulative drift. From the experiments here it seems that Chrome/Edge at least on my Windows10 laptop does some mitigating which means the drift isn't cumulative whereas FF doesn't seem to adjust and the drift can be significant.
It would be interesting to know if others on different systems get equivalent results. Anyway, the basic message is don't rely on such timeouts, it is not a real time system.
Long story short, none of desktop operating systems is real-time os
https://en.m.wikipedia.org/wiki/Real-time_operating_system
Thus, executing a task like calling the callback function is not guaranteed in an exact time. The os does it’s best to juggle all the tasks, take care of power/resource constraints to optimize the performance as a whole. As a result, timings float around a little.
Interestingly, you get a consistent 5 ms shift. I have no explanation for that

time remainder of setInterval JavaScript

I want to be able to run code on the condition that there is time left on a setInterval.
let car = setInterval(function() {
// stuff
}, 2000);
let vehicle = setInterval(function() {
train()
}, 1000);
function train() {
// stuff
// and if car has time left, do this stuff too.
}
At the last line of the train function, I want to check the car's time remaining but don't understand how to go about such a concept.
I guess knowing the exact time left or simply that there is time left is the same to me so which ever is easier.
Remember that timers are potentially quite imprecise, and that setInterval's rules are...interesting...if your handler runs past when the next interval was meant to start. So important to keep in mind.
But if your goal is to know how long it's been since the start of the call to the timer vs when the timer is going to be set to fire again, it's a matter of remembering when you started
var start = Date.now();
...and then later checking how long it's been relative to the interval. For instance:
if (Date.now() - start >= 1900) {
// It's been at least 1900ms since the start of the `vehicle` call,
// so based on a 2000ms interval, in theory you have only 100ms left
}
But, again, note that timers can be quite imprecise if other things are keeping the UI thread busy.
This is not going to be possible. Timers are actually executed outside of the JavaScript runtime and the time specified in them is never a precise measurement - - it's actually the minimum time that the timer could be expected to run. The actual amount of time depends on how busy the JavaScript runtime is and if the runtime is idle at the timer's timeout, the timer's callback function can be run.
So, essentially, you'd have to calculate how much longer the JavaScript execution stack will need in order to become idle, which you can't do because in order to get that time measurement, you have to execute the remaining code. So, you can't get the answer until there's no time left.
But, based on your code, it seems that you could just set a simple "flag" variable that gets set when car runs. So, inside train you can check to see if that flag has been set yet and if not, run the train code and then reset the flag.

Stopwatch not working, it's going way too faster

As I was looking for a simple Stopwatch implementation in JS, I found this code http://codepen.io/_Billy_Brown/pen/dbJeh/
The problem is that it's not working fine, the clock go way too fast. I got 30 seconds on the screen when i got only 23 seconds on my watch.
And I don't understand why. The timer function is called every millisecond and should be updating the time correctly.
setInterval(this.timer, 1);
Is the problem coming from the browser or from the JS code.
Thanks in advance.
The timers in Javascript doesn't have millisecond precision.
There is a minimum time for the interval, which differs depending on the browser and browser version. Typical minimums are 4 ms for recent browsers and 10 ms for a little older browsers.
Also, you can't rely on the callback being called at exact the time that you specify. Javascript is single threaded, which means that if some other code is running when the timer triggers a tick, it has to wait until that other code finishes.
In fact the code you gave is imitating time flow, but it is not synchronized with system time.
Every millisecond it just invokes the function this.time, which performs recounting of millis, seconds and so on
without getting native system time, but just adding 1 to variable representing "imaginary milliseconds".
So we can say that resulting pseudo-time you see depends on your CPU, browser and who knows what else.
On our modern fantastically fast computers the body of this.time function is being executed faster than millisecond (wondering what would happen on Pentium 2 with IE5 on board).
Anyhow there is no chance for the this.time to be executed exactly in particular fixed period on all computers and browsers.
The simplest correct way to show the time passed since startpoint according to the system time is:
<body>
<script>
var startTime = new Date() // assume this initialization to be start point
function getTimeSinceStart()
{
var millisSinceStart = new Date() - startTime
, millis = millisSinceStart % 1000
, seconds = Math.floor(millisSinceStart / 1000)
return [seconds, millis].join( ':' )
}
(function loop()
{
document.title = getTimeSinceStart() // look on the top of page
setTimeout( loop, 10 )
}())
</script>
</body>
P.S. What #Guffa says in his answer is correct (generally for js in browsers), but in this case it does not matter and not affect the problem

Displaying another computer's time on a web page using Javascript? [duplicate]

This question already has answers here:
Clock on webpage using server and system time?
(8 answers)
Closed 9 years ago.
I am working on a very time-sensitive web application. One of the business rules given to me is that the application's behavior must always depend on the time on the web server, regardless of what time is on the client's clock. To make this clear to the user, I was asked to display the server's time in the web application.
To this end, I wrote the following Javascript code:
clock = (function () {
var hours, minutes, seconds;
function setupClock(updateDisplayCallback) {
getTimeAsync(getTimeCallback);
function getTimeCallback(p_hours, p_minutes, p_seconds) {
hours = p_hours;
minutes = p_minutes;
seconds = p_seconds;
setInterval(incrementSecondsAndDisplay, 1000);
}
function incrementSecondsAndDisplay() {
seconds++;
if (seconds === 60) {
seconds = 0;
minutes++;
if (minutes === 60) {
minutes = 0;
hours++;
if (hours === 24) {
hours = 0;
}
}
}
updateDisplayCallback(hours, minutes, seconds);
}
}
// a function that makes an AJAX call and invokes callback, passing hours, minutes, and seconds.
function getTimeAsync(callback) {
$.ajax({
type: "POST",
url: "Default.aspx/GetLocalTime",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response) {
var date, serverHours, serverMinutes, serverSeconds;
date = GetDateFromResponse(response);
serverHours = date.getHours();
serverMinutes = date.getMinutes();
serverSeconds = date.getSeconds();
callback(serverHours, serverMinutes, serverSeconds);
}
})
}
return {
setup: setupClock
};
})();
The function passed in for updateDisplayCallback is a simple function to display the date on the web page.
The basic idea is that the Javascript makes an asynchronous call to look up the server's time, store it on the client, and then update it once per second.
At first, this appears to work, but as time goes by, the displayed time gets behind a few seconds every minute. I left it running overnight, and when I came in the next morning, it was off by more than an hour! This is entirely unacceptable because the web application may be kept open for days at a time.
How can I modify this code so that the web browser will continuously and accurately display the server's time?
Javascript's setInterval is not accurate enough to allow you to keep the time like this.
My solution would be:
Periodically get the server's time in milliseconds (it does not need to be very often as the two clocks will hardly deviate that much)
Get the client time in milliseconds
Calculate the clock deviation between server and client (client-server)
Periodically update the display of the clock by getting the client time and adding the clock deviation
Edit:
To be more accurate, you could measure the round trip time of the server's request, divide it by 2 and factor that delay into the clock deviation. Assuming round trips are symmetrical in their duration, this would give a more accurate calculation.
setInterval is not a reliable way to schedule time critical events. It may take less or more than 1000ms to run your callback depending on how busy JavaScript it is at the moment.
A better approach would be to take a shorter interval and use new Date().getTime() to check if a second has passed.
The minimum interval browsers allow is as high 10.
Thanks for the answers. I have up-voted both answers so far as they contain useful information. However, I am not using the exact answer prescribed in either answer.
What I finally decided on is a bit different.
I wrote about what I learned on my personal web page.
First of all, I now understand that using setInterval(..., 1000) is not good enough to have something done once per second for a long time. However, 'polling' the time with a much shorter interval looking for the second to change seems very inefficient to me.
I decided that it does make sense to keep track of the 'offset' between the server time and the client time.
My final solution is to do the following:
(1) Do an AJAX call to the server to get the time. The function also checks the client time and computes the difference between the server time and the client time, in milliseconds. Due to network latency and other factors, this initial fetch may be off by a few seconds. For my purposes, this is okay.
(2) Execute a tick function. Each time tick executes, it checks how long it has been since the last time tick executed. It will use this time to compute an argument to be passed to setTimeout so that the time display is updated approximately once per second.
(3) Each time the tick function computes the time to be displayed, it takes the client time and adds the difference that was computed in step (1). This way, I don't depend upon the client to have the time set correctly, but I do depend upon the client to accurately measure elapsed time. For my purposes, this is okay. The most important thing is that regardless of how setTimeout may be inaccurate or interrupted by other processes (such as a modal dialog, for instance), the time displayed should always be accurate.

Getting certain frequency with setInterval method

In a javascript code I develop, some function should be called every 1 second. But to be sure that this operation takes place every 1 second, the following code is utilized:
setInterval(doIt, 500);
function doIt() {
var now = (new Date()).getTime();
if(lastUpdate + 1000 >= now) {
/// code...
lastUpdate = now;
}
}
As far as I know setInterval(doIt, 1000) doesn't always mean that it's called every one second.
Is the above solution is a valid one? If not, what do you recommend?
You could use setTimeout instead of setInterval, and make dynamic adjustments each time your function is called. The idea is to set the timeout for a number of milliseconds sufficient to carry you to the next second boundary.
function timeoutFunc() {
// do interesting things
var time = new Date().getTime();
setTimeout(timeoutFunc, 1000 - time % 1000);
}
You'd start it off with:
setTimeout(timeoutFunc, 1000 - new Date().getTime() % 1000);
Synchronizing with the server seems like a bad idea, because you have no way of knowing whether the client clock is synchronized to anything (like the NTP server network). If it's not, then you server synchronizations are going to make things look wrong at the client, because the client clock will always be what seems right.
well setInterval IS defined in milliseconds. so it means its called every X millisdconds.
however the system can freeze or something like that!
but theres no practical better solution, you approach is fine.
if you really have an extensive javascript client application the results could stretch a little bit.
a possible solution for that is to get the system time and have a counter in your function. then ever X executions you align with the system clock, calculate how many function calls you should have until now and speed up the interval or slow it down.
this is as far as you can get to perfection. but it will be only a matter of milliseconds and probably not worth the effort.
may i ask what you are developing?

Categories

Resources