I have written a simple JavaScript timer, but I've noticed that it runs at 1/3 speed. This timer is suppose to keep track how many MS has passed. I am unsure what I have done incorrectly.
http://jsfiddle.net/m3vYc/
time = 10000;
timer = setInterval( function() {
time--;
$('#timer').text(time);
}, 1);
Your error is in assuming that your computer can keep timers of 1 millisecond.
Some browsers will use the computer's clock, which in Windows ticks every 16ms (1/60th of a second, ie the framerate of your screen). Others will override this for a somewhat more accurate 3ms, which is why you are seeing a result of 1/3 speed.
Instead, use Delta Timing:
var start = new Date().getTime();
setInterval(function() {
var now = new Date().getTime();
var elapsed = now-start;
var timeleft = 10000-elapsed;
$("#timer").text(timeleft);
},25);
Demo
Firing a function on each millisecond will clog your browser pretty fast. After all, jQuery is performing a DOM manipulation and it does take a real timelapse, even if tiny.
You should:
fire it with a higher interval,
instead of keeping track of a global time variable, use the browser current timestamp with new Date().getTime()
Add the function to the stack to avoid itself from becoming an obstacle
something like:
var time=new Date().getTime()+10000;
timer = setInterval( function() {
setTimeout(function() {
var timediff=time-new Date().getTime();
$('#timer').text(timediff);
},0);
}, 100);
setting timeout to 0 will fire it inmediately unless there's something enqueued in the stack.
Related
Something that has always bugged me is how unpredictable the setTimeout() method in Javascript is.
In my experience, the timer is horribly inaccurate in a lot of situations. By inaccurate, I mean the actual delay time seems to vary by 250-500ms more or less. Although this isn't a huge amount of time, when using it to hide/show UI elements the time can be visibly noticeable.
Are there any tricks that can be done to ensure that setTimeout() performs accurately (without resorting to an external API) or is this a lost cause?
Are there any tricks that can be done
to ensure that setTimeout() performs
accurately (without resorting to an
external API) or is this a lost cause?
No and no. You're not going to get anything close to a perfectly accurate timer with setTimeout() - browsers aren't set up for that. However, you don't need to rely on it for timing things either. Most animation libraries figured this out years ago: you set up a callback with setTimeout(), but determine what needs to be done based on the value of (new Date()).milliseconds (or equivalent). This allows you to take advantage of more reliable timer support in newer browsers, while still behaving appropriately on older browsers.
It also allows you to avoid using too many timers! This is important: each timer is a callback. Each callback executes JS code. While JS code is executing, browser events - including other callbacks - are delayed or dropped. When the callback finishes, additional callbacks must compete with other browser events for a chance to execute. Therefore, one timer that handles all pending tasks for that interval will perform better than two timers with coinciding intervals, and (for short timeouts) better than two timers with overlapping timeouts!
Summary: stop using setTimeout() to implement "one timer / one task" designs, and use the real-time clock to smooth out UI actions.
.
REF; http://www.sitepoint.com/creating-accurate-timers-in-javascript/
This site bailed me out on a major scale.
You can use the system clock to compensate for timer inaccuracy. If you run a timing function as a series of setTimeout calls — each instance calling the next — then all you have to do to keep it accurate is work out exactly how inaccurate it is, and subtract that difference from the next iteration:
var start = new Date().getTime(),
time = 0,
elapsed = '0.0';
function instance()
{
time += 100;
elapsed = Math.floor(time / 100) / 10;
if(Math.round(elapsed) == elapsed) { elapsed += '.0'; }
document.title = elapsed;
var diff = (new Date().getTime() - start) - time;
window.setTimeout(instance, (100 - diff));
}
window.setTimeout(instance, 100);
This method will minimize drift and reduce the inaccuracies by more than 90%.
It fixed my issues, hope it helps
I had a similar problem not long ago and came up with an approach which combines requestAnimationFrame with performance.now() which works very effectively.
Im now able to make timers accurate to approx 12 decimal places:
window.performance = window.performance || {};
performance.now = (function() {
return performance.now ||
performance.mozNow ||
performance.msNow ||
performance.oNow ||
performance.webkitNow ||
function() {
//Doh! Crap browser!
return new Date().getTime();
};
})();
http://jsfiddle.net/CGWGreen/9pg9L/
If you need to get an accurate callback on a given interval, this gist may help you:
https://gist.github.com/1185904
function interval(duration, fn){
var _this = this
this.baseline = undefined
this.run = function(){
if(_this.baseline === undefined){
_this.baseline = new Date().getTime()
}
fn()
var end = new Date().getTime()
_this.baseline += duration
var nextTick = duration - (end - _this.baseline)
if(nextTick<0){
nextTick = 0
}
_this.timer = setTimeout(function(){
_this.run(end)
}, nextTick)
}
this.stop = function(){
clearTimeout(_this.timer)
}
}
shog9's answer is pretty much what I'd say, although I'd add the following about UI animation/events:
If you've got a box that's supposed to slide onto the screen, expand downwards, then fade in its contents, don't try to make all three events separate with delays timed to make them fire one after another - use callbacks, so once the first event is done sliding it calls the expander, once that's done it calls the fader. jQuery can do it easily, and I'm sure other libraries can as well.
If you're using setTimeout() to yield quickly to the browser so it's UI thread can catch up with any tasks it needs to do (such as updating a tab, or to not show the Long Running Script dialog), there is a new API called Efficient Script Yielding, aka, setImmediate() that may work a bit better for you.
setImmediate() operates very similarly to setTimeout(), yet it may run immediately if the browser has nothing else to do. In many situations where you are using setTimeout(..., 16) or setTimeout(..., 4) or setTimeout(..., 0) (i.e. you want the browser to run any outstanding UI thread tasks and not show a Long Running Script dialog), you can simply replace your setTimeout() with setImmediate(), dropping the second (millisecond) argument.
The difference with setImmediate() is that it is basically a yield; if the browser has sometime to do on the UI thread (e.g., update a tab), it will do so before returning to your callback. However, if the browser is already all caught up with its work, the callback specified in setImmediate() will essentially run without delay.
Unfortunately it is only currently supported in IE9+, as there is some push back from the other browser vendors.
There is a good polyfill available though, if you want to use it and hope the other browsers implement it at some point.
If you are using setTimeout() for animation, requestAnimationFrame is your best bet as your code will run in-sync with the monitor's refresh rate.
If you are using setTimeout() on a slower cadence, e.g. once every 300 milliseconds, you could use a solution similar to what user1213320 suggests, where you monitor how long it was from the last timestamp your timer ran and compensate for any delay. One improvement is that you could use the new High Resolution Time interface (aka window.performance.now()) instead of Date.now() to get greater-than-millisecond resolution for the current time.
You need to "creep up" on the target time. Some trial and error will be necessary but in essence.
Set a timeout to complete arround 100ms before the required time
make the timeout handler function like this:
calculate_remaining_time
if remaining_time > 20ms // maybe as much as 50
re-queue the handler for 10ms time
else
{
while( remaining_time > 0 ) calculate_remaining_time;
do_your_thing();
re-queue the handler for 100ms before the next required time
}
But your while loop can still get interrupted by other processes so it's still not perfect.
Here's an example demoing Shog9's suggestion. This fills a jquery progress bar smoothly over 6 seconds, then redirects to a different page once it's filled:
var TOTAL_SEC = 6;
var FRAMES_PER_SEC = 60;
var percent = 0;
var startTime = new Date().getTime();
setTimeout(updateProgress, 1000 / FRAMES_PER_SEC);
function updateProgress() {
var currentTime = new Date().getTime();
// 1000 to convert to milliseconds, and 100 to convert to percentage
percent = (currentTime - startTime) / (TOTAL_SEC * 1000) * 100;
$("#progressbar").progressbar({ value: percent });
if (percent >= 100) {
window.location = "newLocation.html";
} else {
setTimeout(updateProgress, 1000 / FRAMES_PER_SEC);
}
}
This is a timer I made for a music project of mine which does this thing. Timer that is accurate on all devices.
var Timer = function(){
var framebuffer = 0,
var msSinceInitialized = 0,
var timer = this;
var timeAtLastInterval = new Date().getTime();
setInterval(function(){
var frametime = new Date().getTime();
var timeElapsed = frametime - timeAtLastInterval;
msSinceInitialized += timeElapsed;
timeAtLastInterval = frametime;
},1);
this.setInterval = function(callback,timeout,arguments) {
var timeStarted = msSinceInitialized;
var interval = setInterval(function(){
var totaltimepassed = msSinceInitialized - timeStarted;
if (totaltimepassed >= timeout) {
callback(arguments);
timeStarted = msSinceInitialized;
}
},1);
return interval;
}
}
var timer = new Timer();
timer.setInterval(function(){console.log("This timer will not drift."),1000}
Hate to say it, but I don't think there is a way to alleviate this. I do think that it depends on the client system, though, so a faster javascript engine or machine may make it slightly more accurate.
To my experience it is lost effort, even as the smallest reasonable amount of time I ever recognized js act in is around 32-33 ms. ...
There is definitely a limitation here. To give you some perspective, the Chrome browser Google just released is fast enough that it can execute setTimeout(function() {}, 0) in 15-20 ms whereas older Javascript engines took hundreds of milliseconds to execute that function. Although setTimeout uses milliseconds, no javascript virtual machine at this point in time can execute code with that precision.
Dan, from my experience (that includes implementation of SMIL2.1 language in JavaScript, where time management is in subject) I can assure you that you actually never need high precision of setTimeout or setInterval.
What does however matter is the order in which setTimeout/setInterval gets executed when queued - and that always works perfectly.
JavaScript timeouts have a defacto limit of 10-15ms (I'm not sure what you're doing to get 200ms, unless you're doing 185ms of actual js execution). This is due to windows having a standard timer resolution of 15ms, the only way to do better is to use Windows' higher resolution timers which is a system wide setting so can screw with other applications on the system and also chews battery life (Chrome has a bug from Intel on this issue).
The defacto standard of 10-15ms is due to people using 0ms timeouts on websites but then coding in a way that assumes that assumes a 10-15ms timeout (eg. js games which assume 60fps but ask 0ms/frame with no delta logic so the game/site/animation goes a few orders of magnitude faster than intended). To account for that, even on platforms that don't have windows' timer problems, the browsers limit timer resolution to 10ms.
Here are what I use. Since it's JavaScript, I will post both my Frontend and node.js solutions:
For both, I use the same decimal rounding function that I highly recommend you keep at arms length because reasons:
const round = (places, number) => +(Math.round(number + `e+${places}`) + `e-${places}`)
places - Number of decimal places at which to round, this should be safe and should avoid any issues with floats (some numbers like 1.0000000000005~ can be problematic). I Spent time researching the best way to round decimals provided by high-resolution timers converted to milliseconds.
that + symbol - It is a unary operator that converts an operand into a number, virtually identical to Number()
Browser
const start = performance.now()
// I wonder how long this comment takes to parse
const end = performance.now()
const result = (end - start) + ' ms'
const adjusted = round(2, result) // see above rounding function
node.js
// Start timer
const startTimer = () => process.hrtime()
// End timer
const endTimer = (time) => {
const diff = process.hrtime(time)
const NS_PER_SEC = 1e9
const result = (diff[0] * NS_PER_SEC + diff[1])
const elapsed = Math.round((result * 0.0000010))
return elapsed
}
// This end timer converts the number from nanoseconds into milliseconds;
// you can find the nanosecond version if you need some seriously high-resolution timers.
const start = startTimer()
// I wonder how long this comment takes to parse
const end = endTimer(start)
console.log(end + ' ms')
You could consider using the html5 webaudio clock which uses the system time for better accuracy
So I've got this JavaScript clock I'm working on and I want it to be perfectly synced with the clients' system clock. I know how to get the current time using a Date object and I know how to run the update function every 60000 milliseconds (1 minute). The thing is that the client might load the page when half a minute has already passed, making the clock lag behind with 30 seconds. Is there any way to just run the update function when the minute-variable actually changes? (I only want minute-precision.)
How I get the current time:
var time = new Date();
var currentHour = time.getHours();
var currentMinute = time.getMinutes();
How I run the update function every 60000 ms:
setInterval(update,60000); //"update" is the function that is run
When the user logs in, get the current time and seconds of the minute, subtract 60 to get the remaining seconds, then multiply to set the timer
var time = new Date(),
secondsRemaining = (60 - time.getSeconds()) * 1000;
setTimeout(function() {
setInterval(update, 60000);
}, secondsRemaining);
First, you have to understand that timers in javascript are not guaranteed to be called on time so therefore you cannot be perfectly synced at all times - javascript just isn't a real-time language like that. It is single threaded so a timer event has to wait for other javascript that might be executing at the time to finish before a timer can be executed. So, you must have a design that still does as best as possible even if the timer is delayed (called later than it's supposed to be).
If you wanted to try to stay as close to aligned and do the fewest screen updates and be the most friendly to mobile battery life, I'd suggest this self-aligning code which realigns itself on each tick based on the time remaining until the next minute change:
function runClock() {
var now = new Date();
var timeToNextTick = (60 - now.getSeconds()) * 1000 - now.getMilliseconds();
setTimeout(function() {
update();
runClock();
}, timeToNextTick);
}
// display the initial clock
update();
// start the running clock display that will update right on the minute change
runClock();
This has the advantage that it only calls the update once on the next minute boundary.
Working demo: http://jsfiddle.net/jfriend00/u7Hc5/
var time = new Date();
var currentHour = time.getHours();
var currentMinute = time.getMinutes();
var currentSecond = time.getSeconds();
var updateinterval = setInterval(startTimer,(60-currentSecond)*1000);
function startTimer(){
clearInterval(updateinterval);
setInterval(update,60000);
}
function update(){
var time = new Date();
console.log(time.getSeconds());
}
I would set an interval to run each second, then check if time.getSeconds() == 0. This way you could execute an action whenever a new minute starts, based on the client time.
I am trying to run a function for each milliseconds, In order to achieve so, I just preferred setInterval concept in javascript. My code is given below,
HTML:
<div id=test>0.0</div>
Script:
var xVal = 0;
var xElement = null;
xElement = document.getElementById("test");
var Interval = window.setInterval(startWatch, 1);
function startWatch(){
xVal += 1;
xElement.innerHTML = xVal;
}
so the above code is working fine. But while I am testing the result with a real clock, the real clock requires 1000 milliseconds to complete 1 second, at the same time the result require more than 1000 milliseconds to complete a second.
DEMO
Can anybody tell me,
Is there any mistakes with my code? If yes then tell me, How to display milliseconds accurately.?
There are no mistakes in your code, but JavaScript timers (setInterval and setTimeout) are not precise. Browsers cannot comply with such a short interval. So I'm afraid there is no way to precisely increment the milliseconds by one, and display the updates, on a web browser. In any case, that's not even visible to the human eye!
A precise workaround would involve a larger interval, and timestamps to calculate the elapsed time in milliseconds:
var start = new Date().getTime();
setInterval(function() {
var now = new Date().getTime();
xElement.innerHTML = (now - start) + 'ms elapsed';
}, 40);
You can't. There is a minimum delay that browsers use. You cannot run a function every millisecond.
From Mozilla's docs:
...4ms is specified by the HTML5 spec and is consistent across browsers...
Source: https://developer.mozilla.org/en-US/docs/Web/API/window.setTimeout#Minimum.2F_maximum_delay_and_timeout_nesting
The DOM can't actually update 1000 times per second. Your monitor can't even display 1000 frames in one second, for that matter. Calculate the difference between the start time and current time in milliseconds within your function and use that:
(function(){
var xElement = document.getElementById("test");
var start = new Date;
(function update(){
xElement.innerHTML = (new Date - start);
setTimeout(update, 0);
})();
}();
Updated fiddle
You can't do so using your method because of the delay rendering the HTML and running the interval. Doing it this way will display the time correctly at about 60FPS.
http://jsfiddle.net/3hEs4/3/
var xElement = null;
var startTime = new Date();
xElement = document.getElementById("test");
var Interval = window.setInterval(startWatch, 17);
function startWatch(){
var currentTime = new Date();
xElement.innerHTML = currentTime - startTime;
}
You might also want to look into using requestanimationframe instead of a hardcoded setInterval like that.
The setInterval callback probably does not happen with millisecond accuracy, since the thread the timer is running on might not even actually be running when the time is up, or the browser throttles events, or any other of quite a few things.
In addition, since most Javascript engines are single threaded, what the implementation of setInterval might do is once it triggers, run your callback, and then reset the clock for the next call. Since you're doing some DOM manipulation, that might take several milliseconds on its own.
In short, you're expecting a Real Time Operating System behavior from an interpreter running inside of another application, on top of what is more than likely not an RTOS.
I had the same question and couldn't find any working solution, so I created one myself. The code below essentially calls five setTimouts every 5 ms, for each ms between 5 and 10. This circumvents the minimum 4 ms constraint, and (having checked in Firefox, Chrome, and Opera) works fairly well.
const start = performance.now();
let newNow = 0;
let oldNow = 0;
const runner = function(reset) {
// whatever is here will run ca. every ms
newNow = performance.now();
console.log("new:", newNow);
console.log(" diff:", newNow - oldNow);
oldNow = newNow
if (newNow - start < 1000 && reset) {
setTimeout(function() {
runner(true);
}, 5);
for (let i = 6; i < 11; i++) {
setTimeout(function() {
runner(false);
}, i);
}
}
};
runner(true);
It could of course be written more elegantly, e.g. so that you can more easily customize things like the graduation (e.g. 0.5 ms or 2 ms instead of 1 ms), but anyway the principle is there.
I know that in theory you could call 5 setIntervals instead, but that would in reality cause a drift that would quickly ruin the ms precision.
Note also that there are legitimate cases for the use. (I for one need continual measurement of touch force, which is not possible otherwise.)
I am trying to display several count down timers on same page. now as far as i know there are 2 ways of doing it without using jquery plugins or some other scripts (if you know of a good one please let me know)
starting 1 sec setInterval and a global variable that will contain milliseconds and then just reduce -1000 every interval.
creating a function that reduce 1 sec from a global variable and then at the bottom of that function setting a setTimeout of 1 sec that will run that functions so basically recursion every 1 sec.
My question is which of the 2 options will work better and/or faster?
here is demonstrative code for both:
setInterval:
var amount_of_seconds_left = 46800000;
setInterval(function(){
if(amount_of_seconds_left > 1000){
amount_of_seconds_left -= 1000;
}
},1000);
setTimeout:
var amount_of_seconds_left = 46800000;
function startTime(){
if(amount_of_seconds_left > 1000){
amount_of_seconds_left -= 1000;
t=setTimeout(function(){startTime()},1000);
}
}
Both ways could work but i was wondering performance wise which is better and is performance is even an issue with this ?
setInterval and setTimeout don't start after 1000ms e.g. if another script is running, so both can cause delays. It would be better to use the setIntervall to call the display update only and use the the Date object to calculate the exactly remaining time. E.g. after the browser was busy the timer shows the correct time after the next update.
Here an example:
HTML:
<div id="timer1"></div>
<div id="timer2"></div>
javascript:
// update all timer
function updateTimer() {
for (var i in aTimer) {
var oTimer = document.getElementById(aTimer[i].sId);
var iSeconds = parseInt((aTimer[i].iFinished - Date.now()) / 1000);
oTimer.innerHTML = iSeconds;
}
}
// Init all timers with DOM-id and finish time
var aTimer = [
{ sId: 'timer1', iFinished: Date.now() + 46800000 },
{ sId: 'timer2', iFinished: Date.now() + 780000}
];
// call display update
setInterval(function() {
updateTimer();
}, 333);
I belive that the setInterval code executes every 1000ms exactly, while the setTimeout waits 1000ms, runs the function, which takes some ms, then sets another timeout. So the wait period is actually greater than 1000ms.
From this post:
setTimeout or setInterval?
I have a scenario where one client PC will be driving multiple LCD displays, each showing a single browser window. These browser windows show different data which is on an animated cycle, using jquery.
I need to ensure that both browsers can be synched to rotate at exactly the same time, otherwise they'll animate at different times.
So my question is - can I trigger jquery to alternate the content based on the local PC clock?
eg each time the clock seconds == 0, show version 1, each time clock seconds == 30, show version 2 etc?
This is (in my experience) the most precise way of getting timers to trigger as closely as possible to a clock time:
// get current time in msecs to nearest 30 seconds
var msecs = new Date().getTime() % 30000;
// wait until the timeout
setTimeout(callback, 30000 - msecs);
Then, in the callback, once everything is done, do the same again to trigger the next event.
Using setInterval causes other problems, including clock drift. The calculation based on the current time accounts for the time executing the callback itself.
You'll still also need to use Date().getTime() as well to figure out which frame of your animation to show.
The whole thing would look something like this:
function redraw() {
var interval = 30000;
// work out current frame number
var now = new Date().getTime();
var frame = Math.floor(now / interval) % 2; // 0 or 1
// do your stuff here
.. some time passes
// retrigger
now = new Date().getTime();
setTimeout(redraw, interval - (now % interval));
}
redraw();
working demo at http://jsfiddle.net/alnitak/JPu4R/
The answer is: yes you can.
Use Date.getTime() to monitor time
Trigger your js function every 30 seconds
You could do something like this.
This way, no matter when you launched the different browsers, their rotations would be in sync.
var t=setInterval("check()",1000);
function check(){
var d = new Date();
if(d.getSeconds() == 0)
{
alert('do something');
} else if (d.getSeconds() == 30)
{
alert('do something else');
}
}
Why not launch one window from the other - that way the parent window will have complete control over when the animation starts, because they are in the SAME PROCESS. No clocks required.