首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >倒计时在给定时间内从n到0,负结束值

倒计时在给定时间内从n到0,负结束值
EN

Stack Overflow用户
提问于 2018-05-09 07:30:08
回答 3查看 181关注 0票数 2

我正在编写一个简单的脚本,它应该将给定的值(例如6345.23)动画为0,通过对其进行计数,如果经过指定的时间(例如2 seconds ),它也应该在0结束。

我从简单的逻辑开始:

  • 给定配置:initial valuetime in secinterval
  • 时间以秒为单位,因此将其转换为毫秒。
  • 用ms中的时间除以间隔来计算蜱数
  • 用初始值除以蜱数来计算每条蜱的递减值。

一旦了解了上面的内容,我们就可以简单地做:(简单的模型,而不是实际的代码)

代码语言:javascript
复制
intId = setInterval(function() {
    if(ticks_made === amount_of_ticks) {
        clearInterval(intId);
    } else {
        value -= amount_per_tick;
        // update view
    }
}, interval);

实际代码:

代码语言:javascript
复制
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

代码语言:javascript
复制
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);

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-05-09 08:19:53

kshetline的回答正确地说明了为什么进入负值。当处理分数为IEEE-754的双精度二进制数(在正常范围内,甚至在很高范围内的整数)时,=====可能会出现问题(例如,0.1 + 0.2 == 0.3是假的)。处理像这里的分数值这样小的值,累积的不精确性也是一个因素。这是不可避免的,必须捏造最后一步。

但还有一个更大的问题:你不能依靠计时器来精确地安排时间。许多,很多事情可以阻止他们这样做-其他UI渲染工作,其他脚本,CPU负载,标签是不活跃的,等等。

相反,浏览器上动画的基本技术是:

  • 可以的时候更新
  • 根据时间更新动画中的位置,而不是基于动画的次数
  • 使用requestAnimationFrame使更新与浏览器刷新同步

下面是更新的代码,请参阅注释:

代码语言:javascript
复制
// 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);
  }
}
代码语言:javascript
复制
/* Maximize in-snippet console */
.as-console-wrapper {
  max-height: 100% !important;
}

如果您运行它,然后滚动到"************DELAY************"行,您将看到即使呈现被“另一个进程”所阻碍,我们仍将继续使用适当的下一个值来呈现。

票数 1
EN

Stack Overflow用户

发布于 2018-05-09 07:39:17

你依靠的是ticks_made === amount_of_ticks是完全匹配的。机会是,由于四舍五入,你不会得到一个完全匹配,所以你会更好地做:

代码语言:javascript
复制
if(ticks_made >= amount_of_ticks) {
票数 2
EN

Stack Overflow用户

发布于 2018-05-09 07:47:08

立即将.toFixed()的结果转换为一个数字是有意义的:

代码语言:javascript
复制
let amount_per_tick = +(value / amount_of_ticks).toFixed(5);
let value = +(value - amount_per_tick).toFixed(5);

(注意+符号)

这样,您就不必担心类型强制或其他任何事情,而只需专注于数学。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50247825

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档