5 回答

TA贡献1809条经验 获得超8个赞
解决了,第一次执行方法的时候就已经过了一秒了,所以在初始化end变量的时候就应该减去一秒!
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)
上述代码会造成执行代码的时间累加问题,为了解决这个问题,参考这篇文章,更精确的倒计时应该是这样的:
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); // 代码执行所消耗的时间
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)
感谢各位不吝赐教。

TA贡献1821条经验 获得超6个赞
这个需求其实用setInterval更好,还不会出现你上述的问题:
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)

TA贡献1796条经验 获得超7个赞
js的所有异步时间都不是精确的。
观察一下可以看到每次都不是间隔1000毫秒,
一般的做法是储存下来diff
数值,然后每次循环 从diff
中减去period

TA贡献1995条经验 获得超2个赞
可以参考我下面的代码,其中countDown函数接收倒计时的起始时间和结束时间(ms)。
其基本思路时倒推结束时间之前的所有计时时刻,setTimeout调用时,其时间延迟根据当前时刻与下一个计时时刻的时间差来设置,而不是一个固定值,这样就能避免累计误差。
参数可以比较灵活, 比如起始时间可以是函数调用的当前时间之前,如countDown(Date.now()-5000, Date.now() + 2 * 3600 * 1000),这样的话程序一开始会连续输出已经过去的所有计时时刻;如果起始时间在调用时间之后,那么会等到那个时间之后才开始倒计时,比如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);
}
})();

TA贡献1836条经验 获得超13个赞
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带来的偏差累计
添加回答
举报