利用setTimeout实现的倒计时功能出现跳一秒问题

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)

上面是我写的一个倒计时方法,在控制台打印出的结果却总是跳了一秒,如下所示:

https://img2.mukewang.com/5c8f07e4000195b403890222.jpg

jeck猫
浏览 1791回答 5
5回答

海绵宝宝撒

解决了,第一次执行方法的时候就已经过了一秒了,所以在初始化end变量的时候就应该减去一秒!var period = 60 * 1000 * 60 * 2var endvar date = new Date(end)var interval = 1000function 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)上述代码会造成执行代码的时间累加问题,为了解决这个问题,参考这篇文章,更精确的倒计时应该是这样的:var period = 60 * 1000 * 60 * 2var startTime = new Date().getTime();var count = 0var end = new Date().getTime() + periodvar interval = 1000var currentInterval = intervalfunction loop() {  count++  var offset = new Date().getTime() - (startTime + count * interval); // 代码执行所消耗的时间  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 // 得到下一次循环所消耗的时间  console.log('时:'+h, '分:'+m, '毫秒:'+s, '秒向上取整:'+sCeil, '代码执行时间:'+offset, '下次循环间隔'+currentInterval) // 打印 时 分 秒 代码执行时间 下次循环间隔  setTimeout(loop, currentInterval)}setTimeout(loop, currentInterval)感谢各位不吝赐教。

达令说

这个需求其实用setInterval更好,还不会出现你上述的问题:var period = 60 * 1000 * 60 * 2var endvar date = new Date(end)var interval = 1000var 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)

芜湖不芜

js的所有异步时间都不是精确的。观察一下可以看到每次都不是间隔1000毫秒,一般的做法是储存下来diff数值,然后每次循环 从diff中减去period

拉风的咖菲猫

可以参考我下面的代码,其中countDown函数接收倒计时的起始时间和结束时间(ms)。其基本思路时倒推结束时间之前的所有计时时刻,setTimeout调用时,其时间延迟根据当前时刻与下一个计时时刻的时间差来设置,而不是一个固定值,这样就能避免累计误差。参数可以比较灵活, 比如起始时间可以是函数调用的当前时间之前,如countDown(Date.now()-5000, Date.now() + 2 * 3600 * 1000),这样的话程序一开始会连续输出已经过去的所有计时时刻;如果起始时间在调用时间之后,那么会等到那个时间之后才开始倒计时,比如countDown(Date.now()+5000, Date.now() + 2 * 3600 * 1000)。(function(){&nbsp; &nbsp; var now = Date.now();&nbsp; &nbsp; countDown(now, now + 2 * 3600 * 1000);&nbsp; &nbsp; function countDown(start, end){&nbsp; &nbsp; &nbsp; &nbsp; var interval = 1000,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nextTick = start + ((end - start) % interval);&nbsp; &nbsp; &nbsp; &nbsp; var loopTime = function(){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var now = Date.now();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while(now >= nextTick){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; showTime(end - nextTick);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nextTick += interval;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(nextTick <= end){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setTimeout(arguments.callee, nextTick - now);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; loopTime();&nbsp; &nbsp; }&nbsp; &nbsp; function showTime(ms){&nbsp; &nbsp; &nbsp; &nbsp; var sTotal = Math.floor(ms/1000),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; h = Math.floor(sTotal/3600),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m = Math.floor(sTotal%3600/60),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; s = Math.floor(sTotal%60),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; timeStr = ('0' + h).slice(-2) + ':' +&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ('0' + m).slice(-2) + ':' +&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ('0' + s).slice(-2);&nbsp; &nbsp; &nbsp; &nbsp; console.log(timeStr);&nbsp; &nbsp; }})();

开心每一天1111

var period = 60 * 1000 * 60 * 2var endvar date = new Date(end)var interval = 100var diff,h,hdiff,m,mdiff,s, res, res_tmp;var loop = function () {&nbsp; if (!end) { end = new Date().getTime() + period }&nbsp; diff = end - new Date().getTime()&nbsp; h = Math.floor(diff / (60 * 1000 * 60))&nbsp; hdiff = diff % (60 * 1000 * 60)&nbsp; m = Math.floor(hdiff / (60 * 1000))&nbsp; mdiff = hdiff % (60 * 1000)&nbsp; s = Math.floor(mdiff / (1000))&nbsp; res_tmp = [h, m, s].join('-');&nbsp; if (!res || res != res_tmp) {&nbsp; &nbsp; res = res_tmp;&nbsp; &nbsp; console.log(res)&nbsp; }&nbsp; setTimeout(loop, interval)}setTimeout(loop, interval)降低时间间隔。来排除setTimeout带来的偏差累计
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript