带断点的秒表加起来不正确
Stopwatch with breakpoints not adding up correctly
我有一个主秒表,每步有 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 中。任何指导将不胜感激。
您正在停止一个计时器,并在下一行启动下一个。您的问题部分在于时间在这两个方法调用之间流逝。
此外,您的 'stop' 方法甚至不使用当前时间,它只是从上次更新时追溯停止它,它不会执行最终 _update
。
如果您真的希望它精确相加,请在您的 updateMiniTimers
方法中使用 Date.now()
,并将其传递给两个调用以确保它们 stop/start 在时间,并在 stop
调用后进行最终渲染。
一般来说,在方法内:
method() {
var a = Date.now();
var b = Date.now();
}
a和b绝对不能保证相同,没有方法调用是瞬时的。
你说的是 20 毫秒的延迟,这可能是由多种原因造成的。
- 正如 Flynn1179 所建议的那样,在对
Date.now()
的调用之间可能存在
- JavaScript的
setInterval
漂移了!这里是 a bin to prove it。您真的不能指望在单线程上运行的语言能够非常准确地每 10 毫秒安排一次任务,而您的 _update
方法恰恰需要这样。
- 您忽略了厘秒计数器中的 0-9 毫秒,这在主计时器中已计算在内。这可能是最大的影响因素。例如,假设迷你手表 A 为 15 毫秒,迷你手表 B 为 15 毫秒。小表A会显示'01',小表B会显示'01',但主表会显示'03',因为已经过了30ms。
为了正确解决这个问题,我建议您重新设计您的解决方案,以便将所有秒表包装在一个 StopwatchManager
中,这样可以同时呈现所有秒表并通过添加来计算主表的总时间迷你手表的时代。您可能还想研究使用 requestAnimationFrame
进行渲染而不是 setInterval
.
我同意法拉兹关于可能原因的看法。我还会检查分区中的舍入错误。无论如何,如果你想让它更健壮和可扩展,你可以将你的时间点视为不断扩展的列表中的元素。每当秒表开始时,您将列表中最后一个元素的索引记录为起点,每当一个结束时,您将最后一个元素的索引记录为终点。这将使您拥有准确的计时器层次结构。
我有一个主秒表,每步有 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 中。任何指导将不胜感激。
您正在停止一个计时器,并在下一行启动下一个。您的问题部分在于时间在这两个方法调用之间流逝。
此外,您的 'stop' 方法甚至不使用当前时间,它只是从上次更新时追溯停止它,它不会执行最终 _update
。
如果您真的希望它精确相加,请在您的 updateMiniTimers
方法中使用 Date.now()
,并将其传递给两个调用以确保它们 stop/start 在时间,并在 stop
调用后进行最终渲染。
一般来说,在方法内:
method() {
var a = Date.now();
var b = Date.now();
}
a和b绝对不能保证相同,没有方法调用是瞬时的。
你说的是 20 毫秒的延迟,这可能是由多种原因造成的。
- 正如 Flynn1179 所建议的那样,在对
Date.now()
的调用之间可能存在
- JavaScript的
setInterval
漂移了!这里是 a bin to prove it。您真的不能指望在单线程上运行的语言能够非常准确地每 10 毫秒安排一次任务,而您的_update
方法恰恰需要这样。 - 您忽略了厘秒计数器中的 0-9 毫秒,这在主计时器中已计算在内。这可能是最大的影响因素。例如,假设迷你手表 A 为 15 毫秒,迷你手表 B 为 15 毫秒。小表A会显示'01',小表B会显示'01',但主表会显示'03',因为已经过了30ms。
为了正确解决这个问题,我建议您重新设计您的解决方案,以便将所有秒表包装在一个 StopwatchManager
中,这样可以同时呈现所有秒表并通过添加来计算主表的总时间迷你手表的时代。您可能还想研究使用 requestAnimationFrame
进行渲染而不是 setInterval
.
我同意法拉兹关于可能原因的看法。我还会检查分区中的舍入错误。无论如何,如果你想让它更健壮和可扩展,你可以将你的时间点视为不断扩展的列表中的元素。每当秒表开始时,您将列表中最后一个元素的索引记录为起点,每当一个结束时,您将最后一个元素的索引记录为终点。这将使您拥有准确的计时器层次结构。