倒计时的秒数显示不正常。太慢。点解。。。 ??
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<h2>毫秒的倒计时</h2>
<div id="timer2"></div>
<script>
var countdown = function(gid,time){
try {
if (time<=0) {
} else {
var ms = Math.floor(time%1000);
var s = Math.floor(time/1000%60);
var m = Math.floor(time/1000/60%60);
var h =Math.floor(time/1000/60/60%24);
h=h>9?h:'0'+h;
m=m>9?m:'0'+m;
s=s>9?s:'0'+s;
ms=ms>9?ms:'0'+ms;
if (parseInt(h)>0) {
var str = h+':'+m+':'+s;
} else {
var str = m+':'+s+':'+ms;
}
document.getElementById('timer2').innerHTML = str;
setTimeout(function(){
countdown(gid,time-1);
},1);
}
} catch (e) {
if (typeof(console) == 'object') {
console.log(e);
}
}
};
setTimeout(function(){countdown('timer2',99999)},1);
</script>
</body>
</html>
1
oott123 2016-04-18 22:39:49 +08:00 via Android
定时器设一毫秒一次不太靠谱的,间隔实际上没那么短。
建议你记录下开始时间,通过当前时间和开始时间的计算获取时间差,而不是每次 -1ms |
2
cevincheung OP @oott123 了解。不过还是想知道这个问题是为什么。- -# 秒数跑的好慢。复制的别人的代码稍微改了一下,别人的跑的很正常。但是我改后的秒数跑的好慢好慢。就是不知道为什么。
|
3
oott123 2016-04-18 23:50:37 +08:00 via Android 1
@cevincheung 原因没仔细想过,应该和 event loop 有关,印象中来说这个最短延迟在 4~15 ms 之间。
你不应当依赖 setTimeout 作为准确的计时器,它可能被多方因素影响,还可能导致累积误差。 |
4
bzw875 2016-04-19 00:20:38 +08:00 1
setTimeout 和 setInterval 是个不准时的定时器,你就记录个开始时间然后和当前时间相减吧。前面有 while(true) ;后面的定时器就不会走了,定时器有赖于进程的空闲才会执行。
|
5
wdhwg001 2016-04-19 00:42:29 +08:00 via iPhone 1
事实上这玩意有个最短时间的,基于某种电池保护策略,具体每个浏览器不一样,而且好像还可以通过在页面里加动态内容使得最小时间缩短…
但是不要在毫秒级的地方苛求 js 什么,我曾经为了毫秒级跑过无数个 jsperf ,最后发现相当一部分 best practice 是根本不存在的, ie 、 ff 和 chrome 各不一样, chrome 对最佳实践优化的多一些,而 ff 和 ie 就很少出现更复杂鲁棒的用法反而性能高的诡异状况… |
6
YuJianrong 2016-04-19 01:00:38 +08:00
setTimeout 时间延迟比较长的原因很简单……因为标准就是这样的……
https://html.spec.whatwg.org/multipage/webappapis.html#timers 8. If nesting level is greater than 5, and timeout is less than 4, then increase timeout to 4. nesting level 是指这个 timer 是被另一个 timer 回调函数递归调用的深度,前 4 个递归的 timeout 按原时间调用,第 5 个开始延时会增加到至少 4ms 当然,除了这个因素之外,还有你的各种处理也会消耗时间;回调也是在 JS 线程开始运转,消息队列在 timer 之前跑完才跑,所以间隔当然不只是设置的那点时间了。 不用说正确方法当然是取时间来处理。 |
7
YuJianrong 2016-04-19 01:10:14 +08:00
@wdhwg001 和电池保护什么的没关系请不要乱说哦~~
顺便其实上面这个是 html5 新标准,最早的标准是说 setTimeout 都是至少 4ms ,后来改成如果是另一个 timer 的回调调用的时候(也就是可能成为递归)才至少 4ms ,最新的改成了上面这个。 Firefox 5.0 之前的版本最短时间是 10ms ( from mdn )。 根据某人小范围的测试,至少现在的 Chrome 和 firefox 都实现了这个标准: https://github.com/whatwg/html/issues/239 |
8
sunshinewu85 2016-04-19 03:20:16 +08:00 1
核心原因就是: 你的递归( time-1 ) 1000 次 != 时间真正流逝 1000ms ,所以你现在的秒数实际上是程序执行递归自减 1000 次的数字而已~
其它附带原因: @YuJianrong 说得很清楚了 :) |
9
doublleft 2016-04-19 10:04:12 +08:00 1
哦对, setTimeout ,第二个参数,不设置或设置过小的数字,最小为 10 ( ms )
|
10
wdhwg001 2016-04-19 12:41:46 +08:00 via iPhone
@YuJianrong 好像没这么简单吧?可能会涉及到系统中断周期的问题,节能的确可能影响这个, 4ms 是确切可以达到的吗?
|
11
YuJianrong 2016-04-19 13:18:33 +08:00
@wdhwg001 1. 我只谈标准,标准就这么定的,原因什么的其实真无所谓(要谈一下的话其实原因也很简单, HTML 的标准一般来说都是事实标准——因为最早的 setTimeout 实现为了防止 setTimeout(0)造成浏览器锁死,所以故意延迟了时间,之后 chrome 曾试图移除 setTimeout 最小时间限制,结果有些网站就完蛋了,所以后来干脆写进标准)。
2. ms 级精度对现在的系统来说真是小菜一碟,不会有什么系统啦中断啦的原因。连 HTML5 的高精度计时器标准都达到了微秒级精度: https://developer.mozilla.org/en-US/docs/Web/API/Performance/now 3. 节能是不是影响不知道(看浏览器实现吧,比如 Firefox 对于在后台 tab 的 timer 就至少 1000ms 才跑一次),反正标准没写…… 当然介于消息队列实现原理, nested 的 setTimeout(4ms)是肯定不能确切 4ms 运行的, setInterval 有点希望。 |