tags:

views:

46

answers:

4
+4  Q: 

web based timer

Is there anyway to create a variable speed timer in the browser that will give the exact same results for all operating systems and browsers? If I want 140 beats per minute for every user regardless of their computer speed.

I've been using javascript setTimeout() and setInterval() but I think they are dependant on the speed of the computer and the amount of code in the program. How do I incorporate the system clock into a browser? Or any other ideas?

A: 

Best you can use is setInterval() or try and derive something from Date().

Note that the time won't be exact, I think because of JavaScript's single threaded nature.

alex
A: 

The setTimeout() and setInterval() functions are pretty much the best you're going to get. The timeout parameters to these functions are specified in milliseconds, and are not dependent on the overall speed of the computer running the browser.

However, these functions are certainly not hard-real-time functions, and if the browser is off busy doing something else at the time your timeout or interval expires, there might be a slight delay before your callback function is actually called.

Greg Hewgill
+5  A: 

You'll have to use setTimeout or setInterval in your solution, but it will be inaccurate for the following reasons:

  1. Browsers have a minimum timeout, which is NOT 0ms. The cross-browser minimum is somewhere around 14ms.
  2. Timers are inexact. They represent queuing time, not execution time. If something else is executing when your timer fires, your code gets pushed to a queue to wait, and may not actually execute until much later.

You're probably going to want to use setTimeout along with manual tracking of the current time (using Date) to step your program. For your case, try something like this:

function someAction(delta) {
  // ...
}

function beat() {
  var currentTime = +new Date;
  var delta = currentTime - pastTime;

  if (delta > 430) { // 430ms ~ 140bpm
   pastTime = currentTime;
   someAction();
  }

  setTimeout(beat, 107); // 4x resolution
}

var pastTime = +new Date;
beat();

This should approximate 140 beats per minute, using a higher resolution to avoid larger delays. This is just a sample though, you'll probably need to work at it more to get it to perform optimally for your application.

bcherry
(from @gravityboy)Thanks ben that is a great answer. It does a setimeout 4 times then beat() will only call someaction() if it is over the threshold number, correct? What happens if it is called a few milliseconds before the threshold of 430? Then it doesn't get another chance to fire until it waits out the 107 timeout again?What do you think is the smallest number that can be used in the setTimeout?
bcherry
(from @gravityboy continued) Also what do you think about just having a loop without a setimeout, just using...var currentTime = +new Date; var delta = currentTime - pastTime;and it will run and check delta at whatever speed the computer will allow? Literally hundreds of times then call the function when delta is exceded.Is that a runaway loop?p.s. I thought the = +new Date was a typo but is is not. It displays the date in milliseconds? I can't even find that documented anywhere.
bcherry
Yes, you're correct that this could lead to a 100ms delay. This is just a tradeoff in terms of app responsiveness and timer accuracy. If you did `setTimeout` with 0ms, it will execute the fastest the browser allows (~14ms in some), and this will provide the finest resolution, and thus the greatest accuracy. However, this will come at the expense of the rest of your app. For something simple, this should work great, but for complex apps, this might not work so well.
bcherry
The problem with using a loop is that JavaScript is single-threaded and blocking. Thus, entering a code loop will lock the browser until execution has completed. So you can't do that, or else the user can't use you app at all. The best you can do is the `setTimeout` loop I've shown you, with a 0ms timeout. As for `+new Date`, that's just the least code to get the current time in milliseconds. It's equivalent to `(new Date()).getTime()`, which is called by the `valueOf` function, which is called when coerced with `+`.
bcherry
A: 

@bcherry

Thanks ben that is a great answer. It does a setimeout 4 times then beat() will only call someaction() if it is over the threshold number, correct? What happens if it is called a few milliseconds before the threshold of 430? Then it doesn't get another chance to fire until it waits out the 107 timeout again?

What do you think is the smallest number that can be used in the setTimeout?

Also what do you think about just having a loop without a setimeout, just using...

var currentTime = +new Date; var delta = currentTime - pastTime;

and it will run and check delta at whatever speed the computer will allow? Literally hundreds of times then call the function when delta is exceded.

Is that a runaway loop?

p.s. I thought the = +new Date was a typo but is is not. It displays the date in milliseconds? I can't even find that documented anywhere.

gravityboy
comments are comments, not answers, for a reason
vol7ron
Can you explain what do you mean?
gravityboy
I'm going to copy your questions into a comment on my answer, and then respond there.
bcherry
@bcherry you really know what you are talking about because the sample is here with your code in it... http://www.gootar.com/drums/metronome.htm timeout() is 3 and I have delta being displayed. 120 bpm is 500ms but there is always at least 14 more ms tacked on.
gravityboy
@gravityboy: it's okay to comment, but under each question there is a "add comment" link. You know what, you might not be able to because you don't have many points. You may want to edit your post and I'll take your -1 away.
vol7ron