JavaScript 倒计时偏差纠正
解决 setTimeout/setInterval 实现倒计时时的时间偏差问题
问题
使用 setTimeout 或 setInterval 实现倒计时时会出现时间偏差,如何纠正这个偏差?
解答
偏差产生的原因
JavaScript 是单线程执行的,setTimeout 和 setInterval 只是将回调函数加入事件队列,而不是立即执行。当执行栈为空时才会取出队列中的事件执行,这个等待时间就是偏差的来源。
方案一:服务器校准
定时向服务器请求最新时间差,用服务器时间来校准倒计时。
function serverSyncCountdown(endTime) {
function update() {
fetch('/api/server-time')
.then(res => res.json())
.then(data => {
const serverTime = data.timestamp;
const remaining = endTime - serverTime;
if (remaining > 0) {
displayTime(remaining);
setTimeout(update, 1000);
}
});
}
update();
}
方案二:自动调整间隔时间
通过计算偏差来动态调整下次定时器的间隔时间。
function accurateCountdown(duration) {
let startTime = Date.now();
let count = 0;
const interval = 1000;
function tick() {
count++;
// 计算理论上应该经过的时间
const idealTime = count * interval;
// 计算实际经过的时间
const actualTime = Date.now() - startTime;
// 计算偏差
const drift = actualTime - idealTime;
const remaining = duration - count;
if (remaining > 0) {
displayTime(remaining);
// 用间隔时间减去偏差,纠正下次执行时间
setTimeout(tick, interval - drift);
}
}
tick();
}
function displayTime(seconds) {
console.log(`剩余时间: ${seconds}秒`);
}
// 使用示例:60秒倒计时
accurateCountdown(60);
关键点
setTimeout和setInterval的回调不是精确执行,会因为事件队列等待产生偏差- 服务器校准方案适合需要多端同步的场景,但会增加网络请求
- 自动调整间隔方案通过
实际时间 - 理论时间计算偏差,然后从下次间隔中减去偏差值 - 使用
Date.now()获取时间戳比new Date()性能更好 - 递归
setTimeout比setInterval更适合实现精确倒计时
目录