我正在编写一个简单的脚本,它应该将给定的值(例如6345.23)动画为0,通过对其进行计数,如果经过指定的时间(例如2 seconds ),它也应该在0结束。
我从简单的逻辑开始:
initial value、time in sec、interval一旦了解了上面的内容,我们就可以简单地做:(简单的模型,而不是实际的代码)
intId = setInterval(function() {
if(ticks_made === amount_of_ticks) {
clearInterval(intId);
} else {
value -= amount_per_tick;
// update view
}
}, interval);实际代码:
var value = 212.45,
time = 2, // in seconds
interval = 20; // in milliseconds
var time_to_ms = time * 1000,
amount_of_ticks = time_to_ms / interval,
amount_per_tick = (value / amount_of_ticks).toFixed(5);
var start_time = new Date();
var ticks_made = 0;
var intId = setInterval(function() {
if(ticks_made === amount_of_ticks) {
console.log('start time', start_time);
console.log('end time', new Date());
console.log('total ticks: ', amount_of_ticks, 'decresed by tick: ', amount_per_tick);
clearInterval(intId);
} else {
value = (value - amount_per_tick).toFixed(5);
console.log('running', ticks_made, value);
}
ticks_made++;
}, interval);链接do 小提琴 (在控制台中,您可以观察它是如何工作的)
如果您将时间设置为2 (2 seconds)它的ok,但如果您将时间设置为例如2.55 (2.55 seconds),它就不会停止在0上,它会以负值经过并无限期地进行。
我是如何修复它的,所以不管在几秒钟内设置了什么,它总是一个接一个地执行,直到达到完美的0。
var value = 212.45,
time = 2, // in seconds
interval = 20; // in milliseconds
var time_to_ms = time * 1000,
amount_of_ticks = time_to_ms / interval,
amount_per_tick = (value / amount_of_ticks).toFixed(5);
var start_time = new Date();
var ticks_made = 0;
var intId = setInterval(function() {
if(ticks_made === amount_of_ticks) {
console.log('start time', start_time);
console.log('end time', new Date());
console.log('total ticks: ', amount_of_ticks, 'decresed by tick: ', amount_per_tick);
clearInterval(intId);
} else {
value = (value - amount_per_tick).toFixed(5);
console.log('running', ticks_made, value);
}
ticks_made++;
}, interval);
发布于 2018-05-09 08:19:53
kshetline的回答正确地说明了为什么进入负值。当处理分数为IEEE-754的双精度二进制数(在正常范围内,甚至在很高范围内的整数)时,==和===可能会出现问题(例如,0.1 + 0.2 == 0.3是假的)。处理像这里的分数值这样小的值,累积的不精确性也是一个因素。这是不可避免的,必须捏造最后一步。
但还有一个更大的问题:你不能依靠计时器来精确地安排时间。许多,很多事情可以阻止他们这样做-其他UI渲染工作,其他脚本,CPU负载,标签是不活跃的,等等。
相反,浏览器上动画的基本技术是:
requestAnimationFrame使更新与浏览器刷新同步下面是更新的代码,请参阅注释:
// Tell in-snippet console to keep all lines (rather than limiting to 50)
console.config({maxEntries: Infinity});
var value = 212.45,
time = 2.55, // in seconds
time_in_ms = time * 1000,
amount_per_ms = value / time_in_ms,
interval = 100 / 6, // in milliseconds, ~16.66ms is a better fit for browser's natural refresh than 20ms
ticks_made = 0;
// A precise way to get relative milliseconds timings
var now = typeof performance !== "undefined" && performance.now
? performance.now.bind(performance)
: Date.now.bind(Date);
// Remember when we started
var started = now();
// Because of the delay between the interval timer and requestAnimationFrame,
// we need to flag when we're done
var done = false;
// Use the interval to request rendering on the next frame
var intId = setInterval(function() {
requestAnimationFrame(render);
}, interval);
// About half-way in, an artificial 200ms delay outside your control interrupts things
setTimeout(function() {
console.log("************DELAY************");
var stop = now() + 200;
while (now() < stop) {
// Busy-loop, preventing anything else from happening
}
}, time_in_ms / 2);
// Our "render" function (okay, so we just call console.log in this example, but
// in your real code you'd be doing a DOM update)
function render() {
if (done) {
return;
}
++ticks_made;
var elapsed = now() - started;
if (elapsed >= time_in_ms) {
console.log(ticks_made, "done");
done = true;
clearInterval(intId);
} else {
var current_value = value - (amount_per_ms * elapsed);
console.log(ticks_made, current_value);
}
}/* Maximize in-snippet console */
.as-console-wrapper {
max-height: 100% !important;
}
如果您运行它,然后滚动到"************DELAY************"行,您将看到即使呈现被“另一个进程”所阻碍,我们仍将继续使用适当的下一个值来呈现。
发布于 2018-05-09 07:39:17
你依靠的是ticks_made === amount_of_ticks是完全匹配的。机会是,由于四舍五入,你不会得到一个完全匹配,所以你会更好地做:
if(ticks_made >= amount_of_ticks) {发布于 2018-05-09 07:47:08
立即将.toFixed()的结果转换为一个数字是有意义的:
let amount_per_tick = +(value / amount_of_ticks).toFixed(5);
let value = +(value - amount_per_tick).toFixed(5);(注意+符号)
这样,您就不必担心类型强制或其他任何事情,而只需专注于数学。
https://stackoverflow.com/questions/50247825
复制相似问题