V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
cevincheung
V2EX  ›  问与答

JS 白痴问个倒计时的问题

  •  
  •   cevincheung · 2016-04-18 22:35:01 +08:00 · 1898 次点击
    这是一个创建于 3142 天前的主题,其中的信息可能已经有所发展或是发生改变。

    倒计时的秒数显示不正常。太慢。点解。。。 ??

    <!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 条附言  ·  2016-04-19 12:17:54 +08:00
    已换方案,感谢指点。
    11 条回复    2016-04-19 13:18:33 +08:00
    oott123
        1
    oott123  
       2016-04-18 22:39:49 +08:00 via Android
    定时器设一毫秒一次不太靠谱的,间隔实际上没那么短。
    建议你记录下开始时间,通过当前时间和开始时间的计算获取时间差,而不是每次 -1ms
    cevincheung
        2
    cevincheung  
    OP
       2016-04-18 22:43:27 +08:00
    @oott123 了解。不过还是想知道这个问题是为什么。- -# 秒数跑的好慢。复制的别人的代码稍微改了一下,别人的跑的很正常。但是我改后的秒数跑的好慢好慢。就是不知道为什么。
    oott123
        3
    oott123  
       2016-04-18 23:50:37 +08:00 via Android   ❤️ 1
    @cevincheung 原因没仔细想过,应该和 event loop 有关,印象中来说这个最短延迟在 4~15 ms 之间。
    你不应当依赖 setTimeout 作为准确的计时器,它可能被多方因素影响,还可能导致累积误差。
    bzw875
        4
    bzw875  
       2016-04-19 00:20:38 +08:00   ❤️ 1
    setTimeout 和 setInterval 是个不准时的定时器,你就记录个开始时间然后和当前时间相减吧。前面有 while(true) ;后面的定时器就不会走了,定时器有赖于进程的空闲才会执行。
    wdhwg001
        5
    wdhwg001  
       2016-04-19 00:42:29 +08:00 via iPhone   ❤️ 1
    事实上这玩意有个最短时间的,基于某种电池保护策略,具体每个浏览器不一样,而且好像还可以通过在页面里加动态内容使得最小时间缩短…
    但是不要在毫秒级的地方苛求 js 什么,我曾经为了毫秒级跑过无数个 jsperf ,最后发现相当一部分 best practice 是根本不存在的, ie 、 ff 和 chrome 各不一样, chrome 对最佳实践优化的多一些,而 ff 和 ie 就很少出现更复杂鲁棒的用法反而性能高的诡异状况…
    YuJianrong
        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 之前跑完才跑,所以间隔当然不只是设置的那点时间了。

    不用说正确方法当然是取时间来处理。
    YuJianrong
        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
    sunshinewu85
        8
    sunshinewu85  
       2016-04-19 03:20:16 +08:00   ❤️ 1
    核心原因就是: 你的递归( time-1 ) 1000 次 != 时间真正流逝 1000ms ,所以你现在的秒数实际上是程序执行递归自减 1000 次的数字而已~
    其它附带原因: @YuJianrong 说得很清楚了 :)
    doublleft
        9
    doublleft  
       2016-04-19 10:04:12 +08:00   ❤️ 1
    哦对, setTimeout ,第二个参数,不设置或设置过小的数字,最小为 10 ( ms )
    wdhwg001
        10
    wdhwg001  
       2016-04-19 12:41:46 +08:00 via iPhone
    @YuJianrong 好像没这么简单吧?可能会涉及到系统中断周期的问题,节能的确可能影响这个, 4ms 是确切可以达到的吗?
    YuJianrong
        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 有点希望。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5622 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 37ms · UTC 07:07 · PVG 15:07 · LAX 23:07 · JFK 02:07
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.