Stopwatch with breakpoints that do not stack correctly

I have a main stopwatch with 4 mini-stopwatch for each step. After the end time, here is an example of what timers should look like:

MAIN: 00 : 14 : 57 ------------------- MINI1: 00 : 04 . 17 MINI2: 00 : 06 . 40 MINI3: 00 : 02 . 54 MINI4: 00 : 01 . 46 

Mini timers must be added before the main timer, as in this case. With my current timer, it always seems that .02 milliseconds are off, so in this case, instead of 00 : 14 . 57 00 : 14 . 57 they will be added until 00 : 14 . 55 00 : 14 . 55 .

Here is the JSFiddle of my current timers. I think the problem is most likely in the stopwatch.js file, but I'm not sure why this would be so, since I use Date.now() to calculate how much time has passed. Here is the stopwatch.js file, which is the code for the individual stopwatch:

 class Stopwatch { constructor (opts) { this.isOn = false; this.time = 0; this.elem = opts.elem; } start () { this.offset = Date.now(); this.interval = setInterval(() => this._update(), 10); this.isOn = true; } stop () { clearInterval(this.interval); this.offset = null; this.interval = null; this.isOn = false; } reset () { this.time = 0; this._render(); } _update () { this.time += this._getTimePassed(); this._render(); } _getTimePassed () { const now = Date.now(); const timePassed = now - this.offset; this.offset = now; return timePassed; } _timeFormatter (milliseconds) { const padZero = (time) => `0${time}`.slice(-2); const minutes = padZero(milliseconds / 60000 | 0); const seconds = padZero((milliseconds / 1000 | 0) % 60); const centiseconds = padZero((milliseconds / 10 | 0) % 100); return `${minutes} : ${seconds} . ${centiseconds}`; } _render () { this.elem.textContent = this._timeFormatter(this.time); } } 

I have everything inside the JSFiddle I mentioned above, as well as in this gist , if it's easier to read. Any recommendations would be appreciated.

+8
javascript timer stopwatch
source share
3 answers

You are talking about a delay of 20 ms, which can be caused by a number of things.

  • As suggested by Flynn1179, perhaps between calls to Date.now()
  • JavaScript setInterval drifts! And here is bin to prove it . You cannot rely on a language that runs on a single thread to schedule tasks every 10 ms with complete accuracy, and your _update method requires just that.
  • You ignore 0-9ms in the centiseconds counter, which counts in the main timer. This is probably the biggest contribution. For example, say miniwatch A is at 15 ms, and miniwatch B is at 15 ms. The Miniwatch A will display β€œ01,” the miniwatch B will display β€œ01,” but the main clock will display β€œ03,” since 30 ms has passed.

To solve this problem, I would recommend reconfiguring your solution so that you wrap all your stopwatch in StopwatchManager , which displays all your stopwatch at the same time and calculates the total time for your main watch, adding miniwatches. You may also need to use requestAnimationFrame to render instead of setInterval .

+5
source share

You stop one timer, and in the next line - starting from the next. Your problem is partially related to the fact that time passes between these two method calls.

In addition, your "stop" method does not even use the current time, it just retroactively stops it from the moment of the last update, it does not do the final _update .

If you really want this to be specified exactly, take Date.now() in your updateMiniTimers method and pass this for both calls to make sure they stop / start at the same point in time and do the final rendering after a stop .

In general, within the framework of the method:

 method() { var a = Date.now(); var b = Date.now(); } 

a and b are absolutely guaranteed to not match, the method call is not instantaneous.

+1
source share

I agree with Faraz about the possible reasons. I would also check rounding errors in units. In any case, if you want to make it more reliable and scalable, you can think of your points in time as elements in a list that continues to expand. Whenever the stopwatch starts, you record the index of the last item in the list as a starting point, whenever you finish writing the index of the last item as an endpoint. This will allow you to have accurate timer hierarchies.

+1
source share

All Articles