我有一系列开始/停止时间。我基本上想要显示每个条目花费的时间,以及所有条目的总时间。这是我为了尝试这样做而编写的代码:
var selected = (function(){
var doc = document;
var DOM = {
Ulshow : false,
button : doc.querySelector( '.wraper button' ),
input : doc.querySelector( '.wraper input' ),
ul : doc.querySelector( '.wraper ul' )
}
function toggleUl() {
var display = DOM.Ulshow ? 'none' : 'block';
DOM.ul.style.display = display;
DOM.Ulshow = !DOM.Ulshow;
}
function selectLi( e ) {
if ( e.target.tagName.toLowerCase() !== 'li' )
return;
DOM.input.value = e.target.innerHTML;
toggleUl();
}
function bindEvent() {
DOM.button.addEventListener( 'click', toggleUl, false );
DOM.ul.addEventListener( 'click', selectLi, false );
}
function unbindEvent() {
DOM.button.removeEventListener( 'click', toggleUl, false );
DOM.ul.removeEventListener( 'click', selectLi, false );
}
function init() {
bindEvent();
}
init();
return {
unbindEvent : unbindEvent
};
})();
//Now I can invoke the selected.unbindEvent function to unbind click event
seleted.unbindEvent();

然而,我正在失去准确性。如您所见,个别时间不能合计function 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}`;
}
// Example stopwatch times
const timeIntervals = [
{ startTime: 1470679294008, stopTime: 1470679300609 },
{ startTime: 1470679306278, stopTime: 1470679314647 },
{ startTime: 1470679319718, stopTime: 1470679326693 },
{ startTime: 1470679331229, stopTime: 1470679336420 }
];
// Calculate time it took for each entry
const times = timeIntervals.map(time => time.stopTime - time.startTime);
// Run the timeFormatter on each individual time
const individualTimes = times.map(timeFormatter);
// Run the timeFormatter on the sum of all the times
const mainTimer = timeFormatter(times.reduce((a, b) => a + b));
/**
* [
* '00 : 06 . 60',
* '00 : 08 . 36',
* '00 : 06 . 97',
* '00 : 05 . 19'
* ]
*/
console.log(individualTimes);
/**
* 00 : 27 . 13
*/
console.log(mainTimer);
值。无论什么时候,它总是在.01 - .03之间。
有没有办法可以确保时间只显示两个地方,但仍然正确加起来?任何帮助将不胜感激。
我也可以在JSFiddle上使用它,因为它更容易运行。
编辑:目前的答案确实适用于我上面提供的案例,但它并不适用于this之类的所有案例。
答案 0 :(得分:4)
每次显示舍入时间时,您都会失去准确性。 你拥有的圈数越多,问题就越严重:
╔══════╦════════════════════════════════╗
║ Lap ║ Total time (ms) ║
║ Time ╠═══════╦═════════════╦══════════╣
║ (ms) ║ JS ║ Real World ║ Display ║
╠══════╬═══════╬═════════════╬══════════╣
║ 3157 ║ 3157 ║ 3157.5±0.5 ║ 3160±5 ║
║ 2639 ║ 5796 ║ 5797.0±1 ║ 5800±10 ║
║ 3287 ║ 9083 ║ 9084.5±1.5 ║ 9090±15 ║
║ 3106 ║ 12189 ║ 12191.0±2 ║ 12200±20 ║
╚══════╩═══════╩═════════════╩══════════╝
考虑到公差后,不同的总数实际上相互重叠:
换句话说,通过将显示的时间相加,还会增加显示精度的丢失。 没有说明人类失去的这个是真正的问题。
以下是解决方案3的演示。
function run ( set ) {
show ( set === 0
? // Good set
[ { startTime: 1470679294008, stopTime: 1470679300609 },
{ startTime: 1470679306278, stopTime: 1470679314647 },
{ startTime: 1470679319718, stopTime: 1470679326693 },
{ startTime: 1470679331229, stopTime: 1470679336420 } ]
: // Bad set
[ { startTime: 1472104779284, stopTime: 1472104782441 },
{ startTime: 1472104782442, stopTime: 1472104785081 },
{ startTime: 1472104785081, stopTime: 1472104788368 },
{ startTime: 1472104788369, stopTime: 1472104791475 }, ] );
}
function show ( timeIntervals ) {
const sum = (a, b) => a + b;
const roundTime = (ms) => Math.round(ms/10);
function timeFormatter (centi) {
const padZero = (time) => `0${~~time}`.slice(-2);
const minutes = padZero(centi / 6000);
const seconds = padZero((centi / 100) % 60);
const centiseconds = padZero(centi % 100);
return `${minutes} : ${seconds} . ${centiseconds} `;
}
// Calculate time it took for each entry.
const times = timeIntervals.map(time => time.stopTime - time.startTime);
// Rou and run the timeFormatter on each individual time
const roundedTimes = times.map(roundTime);
const individualTimes = roundedTimes.map(timeFormatter);
// Calculate sum of displayed time
const displayedSum = roundedTimes.reduce(sum);
// Sum time and run timeFormatter
const totalTime = roundTime( times.reduce(sum) );
const mainTimer = timeFormatter(totalTime);
let html = '<ol><li>' + individualTimes.join('<li>') + '</ol>Sum: ' + mainTimer;
// Show warning if sum of rounded time is different.
if ( displayedSum !== totalTime )
html += ' (Rounding error corrected)';
document.querySelector('div').innerHTML = html;
}
run(1);
<button onclick='run(0)'>Perfect</button>
<button onclick='run(1)'>Opps</button>
<div></div>
所有计时器,甚至是物理计时器,都必须忍受这种舍入问题。 您是否看过任何制作这种免责声明的计时器?
对于计时器,显示更准确的总时间肯定更准确,即使它不一致。
如果你注意了,你应该看到/意识到javascript时间相对于实时也有这种准确性丢失。 还有一个更大的问题: Date.time与时钟同步,因此不稳定。 鉴于您的样本圈数范围为几秒钟,您甚至可能获得负面圈数。
使用专为定时目的设计的不同计时器Performance.now,可以最大限度地减少错误并解决时间弯曲魔法。
答案 1 :(得分:2)
无法达到你想要的效果。当您将两个数字四舍五入并添加它们时,以及首次添加数字然后舍入它们时,您基本上希望获得相同的结果。
不幸的是,它并没有这样做。例如,Math.round(0.4) + Math.round(0.4)
给出0
,但Math.round(0.4 + 0.4)
给出1。
使数字正确加起来的唯一方法是显示三位小数。
您可以使用(现已删除)answer by Gerardo Furtado中的解决方案获得更准确的结果 - 也就是说,使用Math.round()
来舍入数字,而不是剪切第三个数字,但是在某些情况下仍然无法发挥作用。
答案 2 :(得分:1)
你遇到的问题是因为你的格式化时间只需要几厘秒就可以降低精度。你第一次使用它的方式(没有Math.round())基本上只是修剪Math.floor,只需修剪掉最后一个字符。所以,无论哪种方式,你都会失去精确度。如果你想只显示几厘秒并且你想要用户看到的数学运算,你可以对格式化的数量进行添加,而不是像这样的原始数量:
// this just does the work of adding up the individuals after they've been formatted
const individualAdder = timeFormatter(individualTimes.reduce((total, time) => {
return total + parseFloat(time.replace(/[^0-9]/g, ""));
}, 0) * 10);
/**
* 00 : 27 . 12
*/
console.log(individualAdder);
您还可以以毫秒的精确度显示单个时间,具体取决于您所需的体验。
答案 3 :(得分:-1)
您的解决方案裁掉了最后一位有效数字。
function timeFormatter (milliseconds) {
const padZero = (time) => `0${time}`.slice(-2);
const minutes = padZero(milliseconds / 60000 | 0);
const seconds = padZero((milliseconds / 1000 | 0) % 60);
const centiseconds = `00${milliseconds % 1000}`.slice(-3); //changed
return `${minutes} : ${seconds} . ${centiseconds}`;
}
// Example stopwatch times
const timeIntervals = [
{ startTime: 1470679294008, stopTime: 1470679300609 },
{ startTime: 1470679306278, stopTime: 1470679314647 },
{ startTime: 1470679319718, stopTime: 1470679326693 },
{ startTime: 1470679331229, stopTime: 1470679336420 }
];
// Calculate time it took for each entry
const times = timeIntervals.map(time => time.stopTime - time.startTime);
// Run the timeFormatter on each individual time
const individualTimes = times.map(timeFormatter);
// Run the timeFormatter on the sum of all the times
const mainTimer = timeFormatter(times.reduce((a, b) => a + b));
/**
* [
* '00 : 06 . 601',
* '00 : 08 . 369',
* '00 : 06 . 975',
* '00 : 05 . 191'
* ]
*/
console.log(individualTimes);
/**
* 00 : 27 . 136
*/
console.log(mainTimer);