在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 問答/HTML/ 利用setTimeout實現(xiàn)的倒計時功能出現(xiàn)跳一秒問題

利用setTimeout實現(xiàn)的倒計時功能出現(xiàn)跳一秒問題

var period = 60 * 1000 * 60 * 2
var end
var date = new Date(end)
var interval = 1000
var loop = function () {
  if (!end) { end = new Date().getTime() + period }
  var diff = end - new Date().getTime()
  var h = Math.floor(diff / (60 * 1000 * 60))
  var hdiff = diff % (60 * 1000 * 60)
  var m = Math.floor(hdiff / (60 * 1000))
  var mdiff = hdiff % (60 * 1000)
  var s = Math.floor(mdiff / (1000))
  console.log(h, m, s)
  setTimeout(loop, interval)
}
setTimeout(loop, interval)

上面是我寫的一個倒計時方法,在控制臺打印出的結(jié)果卻總是跳了一秒,如下所示:

clipboard.png

不知這是為何?

回答
編輯回答
有點壞

js的所有異步時間都不是精確的。
觀察一下可以看到每次都不是間隔1000毫秒,
一般的做法是儲存下來diff數(shù)值,然后每次循環(huán) 從diff中減去period

2018年3月30日 17:44
編輯回答
有點壞

可以參考我下面的代碼,其中countDown函數(shù)接收倒計時的起始時間和結(jié)束時間(ms)。

其基本思路時倒推結(jié)束時間之前的所有計時時刻,setTimeout調(diào)用時,其時間延遲根據(jù)當(dāng)前時刻與下一個計時時刻的時間差來設(shè)置,而不是一個固定值,這樣就能避免累計誤差。

參數(shù)可以比較靈活, 比如起始時間可以是函數(shù)調(diào)用的當(dāng)前時間之前,如countDown(Date.now()-5000, Date.now() + 2 * 3600 * 1000),這樣的話程序一開始會連續(xù)輸出已經(jīng)過去的所有計時時刻;如果起始時間在調(diào)用時間之后,那么會等到那個時間之后才開始倒計時,比如countDown(Date.now()+5000, Date.now() + 2 * 3600 * 1000)。


(function(){
    var now = Date.now();
    countDown(now, now + 2 * 3600 * 1000);

    function countDown(start, end){
        var interval = 1000,
            nextTick = start + ((end - start) % interval);
        var loopTime = function(){
            var now = Date.now();
            while(now >= nextTick){
                showTime(end - nextTick);
                nextTick += interval;
            }
            if(nextTick <= end){
                setTimeout(arguments.callee, nextTick - now);
            }
        };
        loopTime();
    }
    function showTime(ms){
        var sTotal = Math.floor(ms/1000),
            h = Math.floor(sTotal/3600),
            m = Math.floor(sTotal%3600/60),
            s = Math.floor(sTotal%60),
            timeStr = ('0' + h).slice(-2) + ':' +
                    ('0' + m).slice(-2) + ':' +
                    ('0' + s).slice(-2);
        console.log(timeStr);
    }
})();
2017年4月7日 11:02
編輯回答
亮瞎她

解決了,第一次執(zhí)行方法的時候就已經(jīng)過了一秒了,所以在初始化end變量的時候就應(yīng)該減去一秒!

var period = 60 * 1000 * 60 * 2
var end
var date = new Date(end)
var interval = 1000
function loop() {
  if (!end) { end = new Date().getTime() + period - interval / 1000 }
  var diff = end - new Date().getTime()
  var h = Math.floor(diff / (60 * 1000 * 60))
  var hdiff = diff % (60 * 1000 * 60)
  var m = Math.floor(hdiff / (60 * 1000))
  var mdiff = hdiff % (60 * 1000)
  var s = Math.floor(mdiff / (1000))
  console.log(h, m, s)
  setTimeout(loop, interval)
}
setTimeout(loop, interval)

上述代碼會造成執(zhí)行代碼的時間累加問題,為了解決這個問題,參考這篇文章,更精確的倒計時應(yīng)該是這樣的:

var period = 60 * 1000 * 60 * 2
var startTime = new Date().getTime();
var count = 0
var end = new Date().getTime() + period
var interval = 1000
var currentInterval = interval

function loop() {
  count++
  var offset = new Date().getTime() - (startTime + count * interval); // 代碼執(zhí)行所消耗的時間
  var diff = end - new Date().getTime()
  var h = Math.floor(diff / (60 * 1000 * 60))
  var hdiff = diff % (60 * 1000 * 60)
  var m = Math.floor(hdiff / (60 * 1000))
  var mdiff = hdiff % (60 * 1000)
  var s = mdiff / (1000)
  var sCeil = Math.ceil(s)
  var sFloor = Math.floor(s)
  currentInterval = interval - offset // 得到下一次循環(huán)所消耗的時間
  console.log('時:'+h, '分:'+m, '毫秒:'+s, '秒向上取整:'+sCeil, '代碼執(zhí)行時間:'+offset, '下次循環(huán)間隔'+currentInterval) // 打印 時 分 秒 代碼執(zhí)行時間 下次循環(huán)間隔

  setTimeout(loop, currentInterval)
}

setTimeout(loop, currentInterval)

感謝各位不吝賜教。

2018年1月7日 23:14
編輯回答
負(fù)我心

這個需求其實用setInterval更好,還不會出現(xiàn)你上述的問題:

var period = 60 * 1000 * 60 * 2
var end
var date = new Date(end)
var interval = 1000
var loop = function () {
  if (!end) { end = new Date().getTime() + period }
  var diff = end - new Date().getTime()
  var h = Math.floor(diff / (60 * 1000 * 60))
  var hdiff = diff % (60 * 1000 * 60)
  var m = Math.floor(hdiff / (60 * 1000))
  var mdiff = hdiff % (60 * 1000)
  var s = Math.floor(mdiff / (1000))
  console.log(h, m, s)
}
setInterval(loop, interval)
2017年10月20日 22:29
編輯回答
解夏

這是個膜法問題啊...

2017年1月19日 01:47
編輯回答
膽怯
var period = 60 * 1000 * 60 * 2
var end
var date = new Date(end)
var interval = 100
var diff,h,hdiff,m,mdiff,s, res, res_tmp;
var loop = function () {
  if (!end) { end = new Date().getTime() + period }
  diff = end - new Date().getTime()
  h = Math.floor(diff / (60 * 1000 * 60))
  hdiff = diff % (60 * 1000 * 60)
  m = Math.floor(hdiff / (60 * 1000))
  mdiff = hdiff % (60 * 1000)
  s = Math.floor(mdiff / (1000))
  res_tmp = [h, m, s].join('-');
  if (!res || res != res_tmp) {
    res = res_tmp;
    console.log(res)
  }
  setTimeout(loop, interval)
}
setTimeout(loop, interval)

降低時間間隔。來排除setTimeout帶來的偏差累計

2018年9月19日 16:34