使用setInterval实现的JS秒表切窗后暂停,如何使其后台运行用于番茄钟?
JS秒表后台运行不暂停的解决方案
问题原因
你当前的实现依赖setInterval每10ms执行一次累加计数,而浏览器为了节省后台标签页的性能开销,会对非活跃标签页的定时器执行做降频甚至暂停处理,间隔越小的定时器受影响越明显,就会出现切走页面后计时停止的问题。
解决思路
放弃靠定时器执行次数累加计时的逻辑,改为用时间戳差值计算实际经过的时长:
- 计时启动时记录当前时间戳,同时保存暂停时已经累计的计时时长
- 每次定时器触发时,用当前时间戳减去启动时间戳,直接换算得到准确的分、秒、毫秒数值
- 就算后台时定时器触发变慢,切回前台后第一次计算就会自动对齐真实时间,不会出现误差
修改后完整代码
// 移除原来的计数变量tens/seconds/minutes,改为时间戳相关变量 let startTime = 0; // 计时启动时的时间戳 let elapsedTime = 0; // 累计已经过的毫秒数 let interval = null; const getSeconds = document.querySelector('.seconds'); const getTens = document.querySelector('.tens'); const getMinutes = document.querySelector('.minutes'); const start = document.querySelector('.start'), stop = document.querySelector('.stop'), reset = document.querySelector('.reset'); start.addEventListener('click', () => { clearInterval(interval); // 启动时计算起始时间:当前时间减去已经过的时长,保证暂停后继续可以接上 startTime = Date.now() - elapsedTime; // 定时器间隔可以调到50ms,足够视觉流畅还更省性能 interval = setInterval(updateTimer, 50); }) stop.addEventListener('click', () => { clearInterval(interval); }) reset.addEventListener('click', () => { clearInterval(interval); // 重置所有时间相关变量 startTime = 0; elapsedTime = 0; // 重置显示 getMinutes.innerHTML = '00'; getSeconds.innerHTML = '00'; getTens.innerHTML = '00'; }) function updateTimer() { // 计算当前已经过的总毫秒数 elapsedTime = Date.now() - startTime; // 换算成分钟、秒、10毫秒单位(对应你原来的tens变量) const totalTens = Math.floor(elapsedTime / 10); const minutes = Math.floor(totalTens / 6000); const seconds = Math.floor((totalTens % 6000) / 100); const tens = totalTens % 100; // 补0更新显示 getMinutes.innerHTML = minutes.toString().padStart(2, '0'); getSeconds.innerHTML = seconds.toString().padStart(2, '0'); getTens.innerHTML = tens.toString().padStart(2, '0'); }
核心改动说明
- 完全移除了计数累加逻辑,所有时间值都从真实时间戳计算得出,不受定时器执行频率影响
- 定时器仅负责刷新页面显示,就算后台时执行次数变少,切回后显示的时间依然准确
- 优化了补0逻辑,用
padStart方法简化了多分支判断代码
内容的提问来源于stack exchange,提问作者cheepmanzee
相关产品推荐
相关产品推荐

