没有正确添加断点的秒表

时间:2016-07-10 01:02:42

标签: javascript timer stopwatch

我有一个主秒表,每个步骤有4个迷你秒表。完成一段时间后,这里有一个定时器应该如何显示的例子:

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

迷你定时器应该加到主计时器上,就像在这种情况下一样。使用我当前的计时器,它似乎总是.02毫秒关闭,因此在这种情况下它们将加起来00 : 14 . 55而不是00 : 14 . 57

这是我当前定时器的JSFiddle。我认为问题最有可能发生在stopwatch.js文件中,但我不确定为什么会出现这种情况,因为我使用Date.now()来计算已经过了多长时间。这是stopwatch.js文件,它是单个秒表的代码:

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);
  }
}

我在上面提到的JSFiddle中以及在gist中完全包含了所有内容,如果它更容易阅读的话。任何指导都将不胜感激。

3 个答案:

答案 0 :(得分:5)

你在谈论20毫秒的延迟,这可能是由很多事情造成的。

  • 正如Flynn1179建议的那样,可能在致电Date.now()
  • 之间
  • JavaScript setInterval漂移!在这里a bin to prove it。您无法真正期望在单个线程上运行的语言能够以每10毫秒完美准确地安排任务,并且您的_update方法只需要这样做。
  • 您忽略了厘秒计数器中的0-9ms,这是在主计时器中计算的。这可能是最大的促成因素。例如,假设迷你秒A为15毫秒,迷你秒B为15毫秒。 Miniwatch A会显示' 01',迷你B会显示' 01'但主手表会显示' 03'自30ms过去了。

为了正确解决这个问题,我建议您重新设计您的解决方案,以便将所有秒表包裹在StopwatchManager中,这会立即渲染所有秒表,并通过添加来计算主表的总时间迷你的时代。您可能还希望使用requestAnimationFrame代替setInterval进行渲染。

答案 1 :(得分:1)

你正在停止一个计时器,在下一行中,开始下一个计时器。你的问题部分是时间在这两个方法调用之间传递。

此外,您的“停止”方法甚至不使用当前时间,它只是从上次更新后追溯停止,它不会进行最终_update

如果您真的想要精确添加,请在Date.now()方法中取updateMiniTimers,并将其传递给两个调用,以确保它们在同一时间点停止/启动,并执行此操作stop来电后的最终渲染。

一般来说,在方法中:

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

a和b绝对不能保证是相同的,没有方法调用是瞬时的。

答案 2 :(得分:1)

我同意法拉兹关于可能的原因。我还会检查各个部门的舍入错误。无论如何,如果你想让它更健壮和可扩展,你可以将你的时间点视为List中不断扩展的元素。每当秒表开始时,您将列表中最后一个元素的索引记录为起始点,每当结束时,您将最后一个元素的索引记录为终点。这将允许您具有准确的计时器层次结构。