I am implementing a live clock in front-end of a large application. For that I have came up with following approach -
JavaScript
var span = document.getElementById('span');
function time() {
var d = new Date();
var s = d.getSeconds();
var m = d.getMinutes();
var h = d.getHours();
span.textContent = h + ":" + m + ":" + s;
}
setInterval(time, 1000);
HTML
<span id="span"></span>
This approach works perfectly fine in isolation, but when this code is integrated in the application which is having several events and function calls, the clock starts lagging by few minutes after say couple of hours until the page is refreshed.
I think this delay is because of setInterval being a web (browser) API and is handled asynchronously it may not execute exactly after 1 second as written in the code every time, if the call stack is not empty after 1 second from time being setInterval is registered due to other function calls/ events present in the call stack of event loop.
So if the page is not refreshed for long time the delay continues to grow. Also the application is written in Angular which is a Single Page application where the page never reloads on navigation because of routing until the page is forcefully refreshed.
So how to build a precise clock in JavaScript which will never delay when integrated in a large application?
Update: Thanks everyone for the response. I think some of you are right, I may be missing some of the details. Actually I was implementing this few days back at work, but have to left this due to some reason and lost track of it. But there was some delay issue for sure working with Date and Timers. Suddenly now this came to my mind and thought asking it here. Extremely sorry for not providing concrete details.
Still I will try to recollect the details and update the question accordingly if possible.
the clock starts lagging by few minutes after say couple of hours until the page is refreshed.
Thats impossible with the code you've shown, new Date should return the correct time, no matter how often you reflect its value to the page.
So if the page is not refreshed for long time the delay continues to grow.
Most browsers today will adjust the timers slightly, so that they are quite accurate on average (e.g. if one timer gets called to late by 1ms, the next will be called 1ms earlier), therefore you can only cause a drift over a longer time if you will leave the page, which will pause the timer. That still shouldn't affect new Date though.
Have a look at the Chromium source
Timers in web browsers get dialled back when the page doesn't have focus. You can't change or prevent that. You're already doing the primary thing that's important: Using the current time to update the clock, so that even if your time function isn't called for three seconds, when it runs it updates with the then-current time, skipping over the intermediate values. (You often see people assuming the timer will run at exactly 1000ms intervals and just adding to the seconds value rather than using the current time, which is incorrect.)
If I were doing this, I'd probably decrease the interval (run the callback more often) and use a chained series of setTimeout rather than a single setInterval, not least because different browsers have historically handled setInterval in different ways.
So for instance:
function time() {
var d = new Date();
var s = d.getSeconds();
var m = d.getMinutes();
var h = d.getHours();
span.textContent = h + ":" + m + ":" + s;
setTimeout(time, 250);
}
time();
But if the page is inactive, the clock will get out of date, because the browser will either completely suspend timer execution or at least markedly dial it back. When the page becomes active again, though, hopefully it'll correct itself after no more than 250ms.
Related
I build a web app and I use setInterval with 500ms timer for some clock.
When the window is active the clock runs perfect, I use that:
var tempTimer = 0;
setInterval(function () {
goTimer()
}, 500);
function goTimer() {
tempTimer++;
$("#timer").val(tempTimer);
}
But the problem is when the window/tab becomes inactive - the interval is changed to 1000ms!
When i focus the window/tab again, it changes back to 500ms.
check this out: http://jsfiddle.net/4Jw37/
Thanks a bunch.
Yes, this behavior is intentional.
See the MDN article:
In (Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2) and Chrome 11,
timeouts are clamped to firing no more often than once per second
(1000ms) in inactive tabs; see bug 633421 for more information about
this in Mozilla or crbug.com/66078 for details about this in Chrome.
And the spec says:
Note: This API does not guarantee that timers will run exactly on
schedule. Delays due to CPU load, other tasks, etc, are to be
expected.
You seem to want a timer that increments every half second. You can do that much more accurately by keeping track of the total time since you started and doing some math.
var tempTimer = 0;
var startedTimer = Date.now();
setInterval(goTimer, 250); // a little more often in case of drift
function goTimer() {
tempTimer = Math.floor((Date.now() - startedTimer) / 500);
$("#timer").val(tempTimer);
}
See this work here: http://jsfiddle.net/4Jw37/2/
So this does update every half second, but it doesn't need to. If it skips a few beats it will fix itself the next time it fires because it's recalculating each time based on the time since it started tracking. The number of times the function runs is now has no effect on the value of the counter.
So put in another way, do not ask how many times you incremented the count. Instead ask how many half second segments have passed since you started.
For time interval, Browsers may not behave similar for both active and inactive window.
What you can do, When you are setting the time interval you can save the timestamp(initial time). On window.onfocus, take on there timestamp (now) find the difference between initial time and now and use that update the tempTimer.
This question already has answers here:
How do browsers pause/change Javascript when tab or window is not active?
(3 answers)
Closed 9 years ago.
Here's the simplest code for reproducing I could think of:
ms = 30; // 1000 ?
num = 1;
function test()
{
num+=ms;
document.getElementById('Submit').value = num; // Using native Javascript on purpose
if (num < 4000)
window.setTimeout(test, ms);
}
test()
I set the ms (milliseconds between iterations) to 30, ran the script and moved to different tab on the browser.
Then I wait for about 10 seconds (the script should finish within 4 seconds) and came back to the tab.
If I used Firefox I saw that the script has not finished, and the numbers are still running (resuming from where I left them, I guess).
Which is annoying enough,
But if I changed ms to 1000 and repeat the above steps, when I come back to the tab I saw the script has indeed already finished.
(The script should still take 4 seconds to finish).
Namely, sometimes Firefox runs window.setTimeout even if the window is out of focus, and sometimes it doesn't. Possibly depending on the duration
On the other hand, this is not happening with Internet Explorer.
It keeps running the script even if the tab is not focused. No matter how I set the ms.
Is that due to some performance considerations of Firefox?
What exactly is happening?
How come such a basic thing is in consistent between browsers,
nowadays?
OR, am I working wrong? Is it a weird way for coding?
I'm just trying repeatedly change the DOM, in a delayed fashion, without using setInterval (because I'm changing the interval it self on the go).
And most important, how should I regard this?
I can't assume my user won't leave the tab.
I want to allow my user to leave the page for as mush as one might like.
If one leaves and come back after half an hour, he/she will see irrelevant animations on the page, still running.
Some of these animations are seen by all the users connecting to the page.
There is no need they will be synchronized in resolution of milliseconds, but I can't start them only when the user put the tab/window in focus.
I'm using Firefox 25.0.1, and IE 11. (Windows 7)
Most modern browsers (especially on mobile devices) suspend execution of scripts in tabs that are out of focus to save CPU cycles (for instance, this is why requestAnimationFrame was brought to life). In the case of timeouts, shorter intervals are actually changed to a different / higher value as the browser vendor sees fit.
What you can do to overcome this (if you really must know the interval between successive executions) is to set a timestamp when the timeout is activated, and compare it with the timestamp when the timeout handler is actually executed. Note that when you're animating it's best to calculate properties of the animated Objects by taking other application variables into account, rather than rely on the amount of calls a particular handler has had.
You could also attach listeners to the window for "(un)focus" Events to know when the user has "come back" to your application. In this event handler you can verify whether a timeout was pending and execute its callback manually, if you must do so.
see the difference: http://jsfiddle.net/qN6eB/
ms = 30; // 1000 ?
num = 1;
start = new Date();
function test()
{
num+=ms;
document.getElementById('Submit').value = num;
if (num < 4000)
window.setTimeout(test, ms);
else
document.getElementById('Time').value = new Date() - start;
}
test()
ms2 = 30; // 1000 ?
num2 = 1;
start2 = new Date();
dueTo = new Date(+new Date()+4000);
function test2()
{
num2+=ms2;
document.getElementById('Submit2').value = num2;
if (new Date() < dueTo)
window.setTimeout(test2, ms2);
else
document.getElementById('Time2').value = new Date() - start2;
}
test2()
setTimeout is not precise for timing. Because the timer doesn't interrupt the process, I'll wait for idle time. I don't know how the browsers are managing it, but an inactive tab probably has a lower priority.
I can think about two solutions :
- Try setInterval (I'm not sure if this will solve your problem or not)
- Instead of incrementing a variable, use a Date object, containing the time at the beginning, and compare it with the current time when the function is executed.
var beginTime = (new Date()).getTime();
var intervalId = setInterval(function() {
var timePassed = (new Date()).getTime() - beginTime;
document.getElementById('Submit').value = timePassed;
if(timePassed >= 4000) {
clearInterval(intervalId);
}
}, 30);
I am developing a stopwatch application using Javascript/jQuery. The problem is that the milliseconds value is out of sync with REAL milliseconds. I am using function setInterval() with the interval of 1 millisecond, still it is causing this problem.
jsFiddle: http://jsfiddle.net/FLv3s/
Please help!
Use setInterval to trigger updates, but use the system time (via new Date()) for the actual time calculations.
To be honest, I tried nearly the same thing as you do now (Creating an accurate Metronome in Javascript only) - to make a long story short: To be absolutely accurate in terms of milliseconds (or lower) is sadly not (yet) possible with javascript only.
For more insight i recommend this question: Does JavaScript provide a high resolution timer?
or to be more precise this blog article: http://ejohn.org/blog/how-javascript-timers-work/
Best regards,
Dominik
Program execution in any language, not just JavaScript, is not realtime. It will take a tiny amount of time to actually run the code to increment your counter and update the view, and that throws the "timing" off.
Additionally, many browsers have a "minimum timeout" length, which varies between 4 and about 16 (the latter being the computer's own clock timer), which will really mess with your code.
Instead, you should use delta timing.
var startTime = new Date().getTime();
setInterval(function() {
var elapsed = new Date().getTime()-startTime;
// update view according to elapsed time
},25);
If you're worried about it looking choppy, consider using requestAnimationFrame instead, to update the timer exactly once per frame - this has the added benefit of not updating when the user switches tabs (but it will still be timing them) because if the tab is not active then there's no need to redraw stuff.
You can use the new performance object to get a more accurate time. Combine this with requestAnimationFrame instead of setInterval:
var startTime = performance.now(),
currentTime,
isRunning = true;
loop();
function loop(timeElapsed) {
currentTime = performance.now();
if (isRunning) requestAnimationFrame(loop);
}
Just subtract startTime from currentTime.
I left timeElapsed which contains time elapsed handed by rAF which you can may use also for something (or just ignore it).
One note though: not all browsers support this yet (and some may use prefix) so for mobile you need to use the standard system time object.
I have a simple JavaScript chronograph that displays on a form field called "d2", it is used to check how long someone takes on doing a specific task:
var milisec=0
var seconds=0
var complemento1=""
document.form1.d2.value='00:00:00'
function display(){
if (milisec>=9){
milisec=0
seconds+=1
}
else{
milisec+=1
}
complemento1=complemento2=complemento3="";
if ((seconds%60)<10) complemento1="0";
if ((Math.floor(seconds/60)%60)<10) complemento2="0";
if ((Math.floor(seconds/3600))<10) complemento3="0";
document.form1.d2.value=complemento3+Math.floor(seconds/3600)+":"+complemento2+(Math.floor(seconds/60)%60)+":"+complemento1+(seconds%60)
setTimeout("display()",100)
}
The problem is that when the person opens a new tab / uses another program the timer stops, and then resumes when the window is focused again (Using Chrome). It has the weirdest behavior, because sometimes it works, sometimes it doesn't.
I saw many posts that needed a script to stop when not on focus, I want the exact opposite and searched for over an hour with no luck. Your help is greatly appreciated!
JavaScript timeouts are not guaranteed be executed at a specific time. For example if the thread is busy with something else at the time when the timer finishes, it will first finish what it is doing and then execute your timer.
Also your function does not take into account the time spend inside the display function, so a little delay will be added for each millisecond.
The correct way to implement a timer is using the system time.
So something like:
//Call at the beggining to save the start time
var start_time = new Date()
// Compute seconds (does not matter when/how often you call it.)
var milliseconds_since_start = new Date().valueOf() - start_time
The Date object can also format this period as a clock for you:
var m = new Date(milliseconds_since_start)
m.getMinutes()+":"+m.getSeconds()
I was reading up on this javascript tutorial:
http://www.switchonthecode.com/tutor...ccordion-menus
Basically, it shows you how to create an accordion using pure javascript, not jquery. All made sense to me until the actual part of tracking the animation. He says "Because of all that, the first thing we do in the animation function is figure out how much time has passed since the last animation iteration."
And then uses this code:
Code:
var elapsedTicks = curTick - lastTick;
lastTick is equal to the value of when the function was called (Date().getTime()) and curTick is equal to the value when the function was received. I don't understand why we are subtracting one from the other right here. I can't imagine that there's any noticeable time difference between these two values. Or maybe I'm missing something. Is that animate() function only called once every time a menu title is clicked or is it called several times to create the incremental animation effect?
setTimeout("animate(" + new Date().getTime() + "," + TimeToSlide + ",'" + openAccordion + "','" + nID + "')", 33);
Thanks for any response.
lastTick is equal to the value of when the function was called
lastTick is equal to the value when the function was previously called, on the last frame of animation. Since then, the script has given control back to the browser, asking to be called back in 33 milliseconds.
So curTick-lastTick will generally be about 33, but it could be much higher if the browser is lagged due to other stuff happening at the same time. This is why time-reading has to be done at all.
More usually in this sort of code, you'd store the time the animation started in a variable, and use setInterval to check it every so often, instead of setting a complete new timeout function each time (especially setting a timeout from a string, which is super-ugly).
eta:
then runs the animate() function, which passes the current time
Nope. Look at the set-timeout call again:
setTimeout("animate(" + new Date().getTime() + ","...
That's making a string. new Date().getTime() is evaluated at timeout-setting time, not at timeout-calling time. It ends up making a string like:
setTimeout("animate(1275139344177, 250, 'Accordion4Content', 'Accordion4Content')", 33)
Which is the time at the end of the last frame, not the time the next frame's timeout will fire.
Putting JavaScript code in a string like this is super-confusing, rife with escaping problems, and generally regarded as really poor practice. It would be clearer to do it with an inline function:
var passTick= new Date().getTime();
setTimeout(function() {
animate(passTick, TimeToSlide, openAccordion, nID);
}, 33);