Why this is important to me
I have a site where I need to have a countdown timer running to show people how much time they have left to complete an action.
This timer will run for days and probably just use MomentJS to say something like "in 4 days" from MomentJS's to() function.
However when we have an hour left to go I'm going to switch over to a countdown by minutes timer, eventually when the minutes get low enough, I'm going to have a seconds timer involved. When we're getting down to the very last few minutes I'm going to even display milliseconds.
The problem
Pretty much there are two main techniques to animate the countdown timer.
setInterval()
requestAnimationFrame()
Well, right away I noticed that the requestAnimationFrame() method was much more smooth to the eye, it works great - especially when I'm displaying milliseconds. However it wasn't long when I noticed that my poor computer started to get a little warm. All of this "animation" is causing quite a load on my CPU. I tried to use CPU monitors, and looked around at ways to see how much load this puts on my CPU but, overall I can't really find a tool that gives me a clear graph of what kind of CPU load my little countdown timer is using.
So, I decided to find a way to limit the FPS and see if that would reduce my problem. And yes, it does. If you use setTimeout() in tandem with requestAnimationFrame() you can set a waiting time before you call your next function.
Which raises the question, if you're using setTimeout() - Why don't you just use setInterval() and forget about the extra optimization that requestAnimationFrame() gives you?
I did some looking around and found another method which simply checks to see if the right amount of interval time has passed since the last time requestAnimationFrame() called your function. I made some optimizations to how this code works and ended up with one of the two functions I'm trying to measure below.
In the end, I'd really like to have a more clear way to measure this - because the activity monitor on my mac is hardly reliable tool to give an accurate reading - and I can't find a way to measure just the code I'm running.
Chrome has some more tools, the profiler, and the timeline - which are both very helpful, but they don't give me the metric I'm looking for - CPU load.
The Code:
Here are four code snippets, which do exactly the same thing - all of them use:
MomentJS
CountdownJS
jQuery
The code is 100% identical, the only difference is how I am limiting the FPS of the animation.
I'd like to find a way to measure (as precisely as possible) the difference between the four functions in how much CPU load they are taking. And then I'd like to then change the FPS around to see if I can find an acceptable load for my application and then I can find the sweet spot - the right amount of FPS, during the different timer stages.
Technique 1 - setTimeout()
var now = moment(); // new Date().getTime();
var then = moment().add(60, 'seconds'); // new Date(now + 60 * 1000);
$(".now").text(moment(now).format('h:mm:ss a'));
$(".then").text(moment(then).format('h:mm:ss a'));
$(".duration").text(moment(now).to(then));
(function timerLoop() {
setTimeout(function(){
$(".difference").text(moment().to(then));
$(".countdown").text(countdown(then, null, countdown.YEARS | countdown.MONTHS | countdown.DAYS | countdown.HOURS | countdown.MINUTES | countdown.SECONDS | countdown.MILLISECONDS).toString());
requestAnimationFrame(timerLoop);
}, 1000/30);
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js" type="text/javascript"></script>
<script src="https://cdn.rawgit.com/mckamey/countdownjs/master/countdown.min.js" type="text/javascript"></script>
<script src="https://code.jquery.com/jquery-3.0.0.min.js" type="text/javascript"></script>
<div>
The time is now: <span class="now"></span>, a timer will go off <span class="duration"></span> at <span class="then"></span>
</div>
<div>The timer is set to go off <span class="difference"></span></div>
<div class="countdown"></div>
Technique 2 - Delta between intervals
var now = moment(); // new Date().getTime();
var then = moment().add(60, 'seconds'); // new Date(now + 60 * 1000);
$(".now").text(moment(now).format('h:mm:ss a'));
$(".then").text(moment(then).format('h:mm:ss a'));
$(".duration").text(moment(now).to(then));
var fps = 30;
var interval = 1000/fps;
var performanceTime = performance.now();
var performanceDelta;
(function updateCountdown(time) {
performanceDelta = time - performanceTime;
if (performanceDelta > interval) {
performanceTime = time - (performanceDelta % interval);
$(".difference").text(moment().to(then));
$(".countdown").text(countdown(then, null, countdown.YEARS | countdown.MONTHS | countdown.DAYS | countdown.HOURS | countdown.MINUTES | countdown.SECONDS | countdown.MILLISECONDS).toString());
}
requestAnimationFrame(updateCountdown);
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js" type="text/javascript"></script>
<script src="https://cdn.rawgit.com/mckamey/countdownjs/master/countdown.min.js" type="text/javascript"></script>
<script src="https://code.jquery.com/jquery-3.0.0.min.js" type="text/javascript"></script>
<div>
The time is now: <span class="now"></span>, a timer will go off <span class="duration"></span> at <span class="then"></span>
</div>
<div>The timer is set to go off <span class="difference"></span></div>
<div class="countdown"></div>
Technique 3 - setInterval()
var now = moment(); // new Date().getTime();
var then = moment().add(60, 'seconds'); // new Date(now + 60 * 1000);
$(".now").text(moment(now).format('h:mm:ss a'));
$(".then").text(moment(then).format('h:mm:ss a'));
$(".duration").text(moment(now).to(then));
var fps = 30;
var interval = 1000/fps;
setInterval(function updateCountdown() {
$(".difference").text(moment().to(then));
$(".countdown").text(countdown(then, null, countdown.YEARS | countdown.MONTHS | countdown.DAYS | countdown.HOURS | countdown.MINUTES | countdown.SECONDS | countdown.MILLISECONDS).toString());
}, interval);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js" type="text/javascript"></script>
<script src="https://cdn.rawgit.com/mckamey/countdownjs/master/countdown.min.js" type="text/javascript"></script>
<script src="https://code.jquery.com/jquery-3.0.0.min.js" type="text/javascript"></script>
<div>
The time is now: <span class="now"></span>, a timer will go off <span class="duration"></span> at <span class="then"></span>
</div>
<div>The timer is set to go off <span class="difference"></span></div>
<div class="countdown"></div>
It would also be interesting to see a completely un-throttled version like so:
Technique 4 - No throttle
var now = moment(); // new Date().getTime();
var then = moment().add(60, 'seconds'); // new Date(now + 60 * 1000);
$(".now").text(moment(now).format('h:mm:ss a'));
$(".then").text(moment(then).format('h:mm:ss a'));
$(".duration").text(moment(now).to(then));
(function timerLoop() {
$(".difference").text(moment().to(then));
$(".countdown").text(countdown(then, null, countdown.YEARS | countdown.MONTHS | countdown.DAYS | countdown.HOURS | countdown.MINUTES | countdown.SECONDS | countdown.MILLISECONDS).toString());
requestAnimationFrame(timerLoop);
})();
// CountdownJS: http://countdownjs.org/
// MomentJS: http://momentjs.com/
// jQuery: https://jquery.com/
// Rawgit: http://rawgit.com/
// Light reading about the requestAnimationFrame pattern:
// http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
// https://css-tricks.com/using-requestanimationframe/
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js" type="text/javascript"></script>
<script src="https://cdn.rawgit.com/mckamey/countdownjs/master/countdown.min.js" type="text/javascript"></script>
<script src="https://code.jquery.com/jquery-3.0.0.min.js" type="text/javascript"></script>
<div>
The time is now: <span class="now"></span>, a timer will go off <span class="duration"></span> at <span class="then"></span>
</div>
<div>The timer is set to go off <span class="difference"></span></div>
<div class="countdown"></div>
Simply Put: How does one measure the CPU load difference between four similar javascript functions?
Does anyone already know which of these is going to be more performant? (I know that is not really a word)
Answering my own question:
The Short Answer:
Worst Performance
Clearly setInterval() is the worst solution. Because setInterval() still runs while you are not on the tab, wasting CPU and therefor battery life.
Best Animation (Microseconds)
Clearly the Delta Interval Math calculation method is the most smooth and most accurate way to calculate interval time. When you combined this algorithm with the accuracy of calculating frames times using performance.now() you can achieve results accurate to the microsecond with your animation frames.
(and yes, even requestAnimationFrame() uses performance.now() time as the first argument it passes to the callback function).
And yes folks, I really mean microseconds. That's 1s/1000ms/1000µs.
Go ahead, test it now. Open up your console and type: performance.now() And you'll get a number that looks like 2132438.165 - those are milliseconds since the browser rendered the first frame.
(Which is extra cool because µ is a greek character +10 nerd points)
Best CPU Performance (Milliseconds)
Combine requestAnimationFrame() (which allows your animation to sleep when you switch tabs) with setTimeout() which can throttle the FPS of your animation to any desired millisecond interval.
Keep in mind however, that the difference between this method and the Delta Interval Math method is very VERY slightly different. I don't even have a way to quantify how small of a difference it is. From what I can tell it might be one fourth to one eighth more efficient. But you lose a lot of smoothness for it. your choice.
The Long Answer:
I'm still looking forward to a better way to do this, perhaps in a way that allows me to compare data between different functions.
Until then, I was able to generate these images using Google's Javascript CPU Profiler
Listing in the order in which I believe they are performant, but with titles that match the original question:
Technique 3 - setInterval()
Technique 1 - setTimeout()
Technique 2 - Delta between intervals
Technique 4 - No throttle
Visual Analysis
Well, from the looks of it, I'd rank the different functions in this order of performance:
setInterval() function.
setTimeout() wrapping therequestAnimationFrame()` call.
Delta Interval Math inside the recursive function called by requestAnimationFrame()
No FPS Throttle simply looping with requestAnimationFrame()
Conclusion: [Edited: 06/25/2016]
The setInterval() function is better than any requestAnimationFrame() pattern that I have found at least for CPU usage reasons ONLY WHILE YOU ARE ON THE TAB.
So if CPU cost or longer battery life are the larger concern for your application, than go with requestAnimationFrame() and throttle the FPS using either:
The setTimeout() method which seams to be a little less work for the CPU (best of both worlds) - but admittedly less smooth than the method below.
or
The Delta Interval Math which seams to be a little bit more smooth of an animation (And using the technique outlines in this Question/Answer with the time from performance.now() and the time reported from the requestAnimationFrame() (which is just the current performance.now() provided in the first argument to the callback function). Because we're using the most accurate algorithm I've seen to calculate the animation frame (You're actually calculating down to the millionth of a second, or a microsecond 1s/1000ms/1000µs). There is not a HUGE difference in the CPU load from this technique and setTimeout() - but there IS a difference (reference the attached images)
Why is requestAnimationFrame() is the bomb-digity?" - Because: when you're not on that tab, it gets turned off by the browser, so your animations are "waiting" for you to come back. AND using performance.now() you're getting microsecond (µs) accuracy on your animation.
It is said that requestAnimationFrame() is an "optimized" way to make sure your animation works along side other browser redrawing so that your animation "fits" with what the browser is doing, it also comes at a 60FPS callback cost.
Steps I took to generate these photos:
Created individual blank HTML files with nothing but absolutely what I needed for the tests.
Rebooted my computer, opened only my chrome browser to an about:blank tab.
Opened each "test benchmark" HTML file I previously created individually and one at a time.
At precisely 50 seconds into the countdown timer I clicked start on Google's Javascript CPU Profiler and precisely 10 seconds later I clicked stop (I used a special clicking macro built into my gamer-mouse's special driver software that works pretty well - Once I click the button it clicks start and 10 seconds later another click on stop - good enough for these photos)
Saved the profile to my computer
Loaded each of the profiles into the profiler tool on the about:blank tab.
Resized the window to frame the data well
Screenshot [shift] + [cmd] + [4] and then you press space on the keyboard to frame the screenshot exactly around the window.
Unresolved Problem:
I still don't have a way to see what the CPU % usage is. This graph leave me wanting for something more detailed. The other Google Javascript CPU Profiler screens are also a little vague in this sense. Maybe I just don't know how to use the tool.
If anyone knows of a better benchmark for testing this, please send an answer over and I'll review it. I hope it's better than this mess. And thanks in advance.
The main issue here is having a way to quantify hard data from one CPU profile to another and compare them. This is what I'm missing the most.
Related
I got this code over here:
var date = new Date();
setTimeout(function(e) {
var currentDate = new Date();
if(currentDate - date >= 1000) {
console.log(currentDate, date);
console.log(currentDate-date);
}
else {
console.log("It was less than a second!");
console.log(currentDate-date);
}
}, 1000);
In my computer, it always executes correctly, with 1000 in the console output. Interestedly in other computer, the same code, the timeout callback starts in less than a second and the difference of currentDate - date is between 980 and 998.
I know the existence of libraries that solve this inaccuracy (for example, Tock).
Basically, my question is: What are the reasons because setTimeout does not fire in the given delay? Could it be the computer that is too slow and the browser automatically tries to adapt to the slowness and fires the event before?
PS: Here is a screenshot of the code and the results executed in the Chrome JavaScript console:
It's not supposed to be particularly accurate. There are a number of factors limiting how soon the browser can execute the code; quoting from MDN:
In addition to "clamping", the timeout can also fire later when the page (or the OS/browser itself) is busy with other tasks.
In other words, the way that setTimeout is usually implemented, it is just meant to execute after a given delay, and once the browser's thread is free to execute it.
However, different browsers may implement it in different ways. Here are some tests I did:
var date = new Date();
setTimeout(function(e) {
var currentDate = new Date();
console.log(currentDate-date);
}, 1000);
// Browser Test1 Test2 Test3 Test4
// Chrome 998 1014 998 998
// Firefox 1000 1001 1047 1000
// IE 11 1006 1013 1007 1005
Perhaps the < 1000 times from Chrome could be attributed to inaccuracy in the Date type, or perhaps it could be that Chrome uses a different strategy for deciding when to execute the code—maybe it's trying to fit it into the a nearest time slot, even if the timeout delay hasn't completed yet.
In short, you shouldn't use setTimeout if you expect reliable, consistent, millisecond-scale timing.
In general, computer programs are highly unreliable when trying to execute things with higher precision than 50 ms. The reason for this is that even on an octacore hyperthreaded processor the OS is usually juggling several hundreds of processes and threads, sometimes thousands or more. The OS makes all that multitasking work by scheduling all of them to get a slice of CPU time one after another, meaning they get 'a few milliseconds of time at most to do their thing'.
Implicity this means that if you set a timeout for 1000 ms, chances are far from small that the current browser process won't even be running at that point in time, so it's perfectly normal for the browser not to notice until 1005, 1010 or even 1050 milliseconds that it should be executing the given callback.
Usually this is not a problem, it happens, and it's rarely of utmost importance. If it is, all operating systems supply kernel level timers that are far more precise than 1 ms, and allow a developer to execute code at precisely the correct point in time. JavaScript however, as a heavily sandboxed environment, doesn't have access to kernel objects like that, and browsers refrain from using them since it could theoretically allow someone to attack the OS stability from inside a web page, by carefully constructing code that starves other threads by swamping it with a lot of dangerous timers.
As for why the test yields 980 I'm not sure - that would depend on exactly which browser you're using and which JavaScript engine. I can however fully understand if the browser just manually corrects a bit downwards for system load and/or speed, ensuring that "on average the delay is still about the correct time" - it would make a lot of sense from the sandboxing principle to just approximate the amount of time required without potentially burdening the rest of the system.
Someone please correct me if I am misinterpreting this information:
According to a post from John Resig regarding the inaccuracy of performance tests across platforms (emphasis mine)
With the system times constantly being rounded down to the last queried time (each about 15 ms apart) the quality of performance results is seriously compromised.
So there is up to a 15 ms fudge on either end when comparing to the system time.
I had a similar experience.
I was using something like this:
var iMillSecondsTillNextWholeSecond = (1000 - (new Date().getTime() % 1000));
setTimeout(function ()
{
CountDownClock(ElementID, RelativeTime);
}, iMillSecondsTillNextWholeSecond);//Wait until the next whole second to start.
I noticed it would Skip a Second every couple Seconds, sometimes it would go for longer.
However, I'd still catch it Skipping after 10 or 20 Seconds and it just looked rickety.
I thought, "Maybe the Timeout is too slow or waiting for something else?".
Then I realized, "Maybe it's too fast, and the Timers the Browser is managing are off by a few Milliseconds?"
After adding +1 MilliSeconds to my Variable I only saw it skip once.
I ended up adding +50ms, just to be on the safe side.
var iMillSecondsTillNextWholeSecond = (1000 - (new Date().getTime() % 1000) + 50);
I know, it's a bit hacky, but my Timer is running smooth now. :)
Javascript has a way of dealing with exact time frames. Here’s one approach:
You could just save a Date.now when you start to wait, and create an interval with a low ms update frame, and calculate the difference between the dates.
Example:
const startDate = Date.now()
setInterval(() => {
const currentDate = Date.now()
if (currentDate - startDate === 1000 {
// it was a second
clearInterval()
return
}
// it was not a second
}, 50)
I'm making a game in JavaScript, using the great requestAnimationFrame(callback) function.
Today I learned that the callback passed to requestAnimationFrame() gets a high resolution time measured since we opened that page. Let's call it ms:
function paint(ms) {
// draw my game
requestAnimationFrame(paint);
}
requestAnimationFrame(paint);
It's all great, but there's one thing I don't quite get.
Function requestAnimationFrame() doesn't do anything when we go to another tab, so the rendering is paused. On the other hand, the time passed to the callback still goes on when we leave. Because of this, I'm not sure how would I make any use of that value. If it worked proportionally with rendering engine, I could use ms to calculate logical time of my game, because relying on requestAnimationFrame() as a rock stable 60 FPS doesn't sound like the greatest idea.
Am I missing something? What's the purpose of the ms parameter if it continues to count when we leave our tab?
That's just a timestamp, it doesn't really count anything. It's indeed generally the same as performance.now() which gives the amount of time since the page is active. As to why, it's just how the DOMHighResTimeStamp's origin has been defined.
We usually use it as a way to know how long time has elapsed since some prior event occurred, that is we store a start_time, then check the current timestamp and we can get the delta time of our animation, regardless of the actual frame-rate.
By the way, no, relying on requestAnimationFrame to be at any fixed frame-rate is really not a good idea, requestAnimationFrame is not tied to any frame-rate by specs, and actually it is recommended to align it with the screen refresh-rate (though only Blink does so).
So you actually need to rely on such a timestamp in order to have a consistent speed across different setups. Doing a simple pos++ at every frame will make your animation run twice faster on a 120Hz monitor than on a 60Hz one (at least in Chrome).
This only makes your idea more complex to perceive how it could be implemented: would your paint-timer go twice faster when the window is moved to a 120Hz monitor?
This timestamp may also help to catch up on long frames, it's not because the system had a hiccup that you necessarily want your animation to last longer.
Similarly, not all cases want the animation logic to stop when the window is blurred. Let's say I have a header with a background animation powered by rAF, I don't really want it to pause when going off-screen, even though it didn't have been painted.
If you want your game logic to pause when the window is blurred, listen for the onvisibilitychange, and save the current timestamp (using performance.now() since we're outside of rAF).
To add to Kaiido's answer. It's also common in apps to limit the time delta. For example a common way framerate independant calculations in apps is to compute the time between frames
let previousTime = 0;
function loop(currentTime) {
const deltaTime = currenTime - previousTime;
previousTime = currentTime;
// use deltaTime in various calculations
posX = posX + velX * deltaTime;
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
But, sometimes collision and or other math can break if deltaTime is too large so games will often add a limiter
// don't let deltaTime be more than a 1/10 of a second
const deltaTime = Math.min(currenTime - previousTime, 1000 / 10);
This mostly removes the need for checking for onvisiblitiychange. Especially if you keep your own animation/game clock.
let previousTime = 0;
let clock = 0;
let clockRate = 1;
function loop(currentTime) {
const deltaTime = Math.min(currenTime - previousTime, 1000 / 10) * clockRate;
previousTime = currentTime;
clock += deltaTime; // update our own clock
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
Now not only will or clock not jump if the player hides the tab but we can set clockRate to 0 if we want things to pause.
Why use your own clock? It lets you easily slow down or speed up time for all calculations that depend on that clock (see clockRate above). Also many app (games) have multiple clocks. They'd compute a different deltaTime for each clock. For example one clock for all objects that need to pause vs clocks need to keep going even even with the app/game is pause. Another might be a clock for the player vs one for the enemies so that when the player uses their "slow time super power" the enemies motions go slow but the player's motions remain at the same speed.
I got this code over here:
var date = new Date();
setTimeout(function(e) {
var currentDate = new Date();
if(currentDate - date >= 1000) {
console.log(currentDate, date);
console.log(currentDate-date);
}
else {
console.log("It was less than a second!");
console.log(currentDate-date);
}
}, 1000);
In my computer, it always executes correctly, with 1000 in the console output. Interestedly in other computer, the same code, the timeout callback starts in less than a second and the difference of currentDate - date is between 980 and 998.
I know the existence of libraries that solve this inaccuracy (for example, Tock).
Basically, my question is: What are the reasons because setTimeout does not fire in the given delay? Could it be the computer that is too slow and the browser automatically tries to adapt to the slowness and fires the event before?
PS: Here is a screenshot of the code and the results executed in the Chrome JavaScript console:
It's not supposed to be particularly accurate. There are a number of factors limiting how soon the browser can execute the code; quoting from MDN:
In addition to "clamping", the timeout can also fire later when the page (or the OS/browser itself) is busy with other tasks.
In other words, the way that setTimeout is usually implemented, it is just meant to execute after a given delay, and once the browser's thread is free to execute it.
However, different browsers may implement it in different ways. Here are some tests I did:
var date = new Date();
setTimeout(function(e) {
var currentDate = new Date();
console.log(currentDate-date);
}, 1000);
// Browser Test1 Test2 Test3 Test4
// Chrome 998 1014 998 998
// Firefox 1000 1001 1047 1000
// IE 11 1006 1013 1007 1005
Perhaps the < 1000 times from Chrome could be attributed to inaccuracy in the Date type, or perhaps it could be that Chrome uses a different strategy for deciding when to execute the code—maybe it's trying to fit it into the a nearest time slot, even if the timeout delay hasn't completed yet.
In short, you shouldn't use setTimeout if you expect reliable, consistent, millisecond-scale timing.
In general, computer programs are highly unreliable when trying to execute things with higher precision than 50 ms. The reason for this is that even on an octacore hyperthreaded processor the OS is usually juggling several hundreds of processes and threads, sometimes thousands or more. The OS makes all that multitasking work by scheduling all of them to get a slice of CPU time one after another, meaning they get 'a few milliseconds of time at most to do their thing'.
Implicity this means that if you set a timeout for 1000 ms, chances are far from small that the current browser process won't even be running at that point in time, so it's perfectly normal for the browser not to notice until 1005, 1010 or even 1050 milliseconds that it should be executing the given callback.
Usually this is not a problem, it happens, and it's rarely of utmost importance. If it is, all operating systems supply kernel level timers that are far more precise than 1 ms, and allow a developer to execute code at precisely the correct point in time. JavaScript however, as a heavily sandboxed environment, doesn't have access to kernel objects like that, and browsers refrain from using them since it could theoretically allow someone to attack the OS stability from inside a web page, by carefully constructing code that starves other threads by swamping it with a lot of dangerous timers.
As for why the test yields 980 I'm not sure - that would depend on exactly which browser you're using and which JavaScript engine. I can however fully understand if the browser just manually corrects a bit downwards for system load and/or speed, ensuring that "on average the delay is still about the correct time" - it would make a lot of sense from the sandboxing principle to just approximate the amount of time required without potentially burdening the rest of the system.
Someone please correct me if I am misinterpreting this information:
According to a post from John Resig regarding the inaccuracy of performance tests across platforms (emphasis mine)
With the system times constantly being rounded down to the last queried time (each about 15 ms apart) the quality of performance results is seriously compromised.
So there is up to a 15 ms fudge on either end when comparing to the system time.
I had a similar experience.
I was using something like this:
var iMillSecondsTillNextWholeSecond = (1000 - (new Date().getTime() % 1000));
setTimeout(function ()
{
CountDownClock(ElementID, RelativeTime);
}, iMillSecondsTillNextWholeSecond);//Wait until the next whole second to start.
I noticed it would Skip a Second every couple Seconds, sometimes it would go for longer.
However, I'd still catch it Skipping after 10 or 20 Seconds and it just looked rickety.
I thought, "Maybe the Timeout is too slow or waiting for something else?".
Then I realized, "Maybe it's too fast, and the Timers the Browser is managing are off by a few Milliseconds?"
After adding +1 MilliSeconds to my Variable I only saw it skip once.
I ended up adding +50ms, just to be on the safe side.
var iMillSecondsTillNextWholeSecond = (1000 - (new Date().getTime() % 1000) + 50);
I know, it's a bit hacky, but my Timer is running smooth now. :)
Javascript has a way of dealing with exact time frames. Here’s one approach:
You could just save a Date.now when you start to wait, and create an interval with a low ms update frame, and calculate the difference between the dates.
Example:
const startDate = Date.now()
setInterval(() => {
const currentDate = Date.now()
if (currentDate - startDate === 1000 {
// it was a second
clearInterval()
return
}
// it was not a second
}, 50)
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.
What are the best practices for moving elements with javascript?
Do you use timeouts or intervals?
Is it bad to have timed events for 10 milliseconds, or will it be precise?
Do you move pixel by pixel, or a certain fraction of the total distance?
If you use intervals, how do you stop the interval when the element is in position?
The last two times I've seen motion in javascript have been with jQuery and Raphael.js, neither of which I can understand the source code of. Are there some good tutorials or code examples anywhere? Is there a simple explanation of the methods jQuery uses?
There is a recent function called requestAnimationFrame which runs a function as soon as possible. This is a good practice since it has been made for animation purposes.
The way it works in terms of coding is the same as setTimeout, e.g. when the function finishes you call requestAnimationFrame.
In the function, you fetch the current time to see how the object should be positioned at that time.
You can cancel a pending function it with cancelRequestAnimationFrame, passing the return value of requestAnimationFrame.
Currently this is not cross-browser and the functions are vendor-prefixed, e.g. webkitRequestAnimationFrame for Chrome.
E.g.: http://jsfiddle.net/pimvdb/G2ThU/1/.
var div = document.getElementById('div');
var animation;
function move() {
var time = Math.round((new Date()).getTime() / 10) % 200;
div.style.left = time + 'px';
animation = requestAnimationFrame(move);
}
document.getElementById("start").onclick = function() {
animation = requestAnimationFrame(move);
}
document.getElementById("stop").onclick = function() {
cancelRequestAnimationFrame(animation);
}
Here you can find a good Javascript Animation tutorial:
http://www.schillmania.com/content/projects/javascript-animation-1
But what you said is right. Jquery Animate uses setTimeout, moving the object based in calculations of duration, position and easing.
Intervals are preferable, I believe, because you only set it once in the code rather than once per frame. It only needs to read the code once and reuse it several times, rather than reading it every time it is created.
10ms is a bit short. The computer can natively support intervals of about 16ms, then more precise timers can be used for faster intervals, however these are very power-consuming. IE9 supports both, depending on the computer's power settings, but ideally you shouldn't need anything faster than 50ms (20 FPS).
I like to move a fraction of the total distance, based on the time that has passed since the animation started. This way, no matter what the speed of the computer and browser, the animation will always take the exact same amount of time. Guaranteed.
Something like:
interval = setInterval(function() {
// do stuff
if( /*animation ended*/) clearInterval(interval);
},time);
jQuery is easy for some, but personally I find nothing beats writing it yourself in plain, old JS. Much easier to understand what's going on exactly, rather than relying on some framework to get it right for you.