如何创建带固定间隔且可指定起始值的JavaScript精确定时器?
解决方案:固定间隔输出 + 指定初始值的定时器
我来帮你解决这两个问题,咱们一步步拆解并修改代码:
问题1:固定间隔100输出(避免重复/跳数)
原代码用50ms轮询+四舍五入到100的方式,会因为定时器精度问题导致同一个数值被多次输出,或者偶尔跳数。核心解决思路是记录上一次输出的数值,只有当当前计算值真正递增到下一个100刻度时才更新输出。
问题2:从指定数值开始计数
需要修改Timer类,让它支持初始化时设置初始累计时间,同时调整重置逻辑,让重启时回到指定的初始值。
修改后的完整代码
JavaScript部分
class Timer { // 修改构造函数,支持传入初始时间,默认0 constructor(initialTime = 0) { this.isRunning = false; this.startTime = 0; this.initialTime = initialTime; // 保存初始时间,用于重置 this.overallTime = initialTime; } _getTimeElapsedSinceLastStart() { if (!this.startTime) { return 0; } return Date.now() - this.startTime; } start() { if (this.isRunning) { return console.error('Timer is already running'); } this.isRunning = true; this.startTime = Date.now(); } stop() { if (!this.isRunning) { return console.error('Timer is already stopped'); } this.isRunning = false; this.overallTime = this.overallTime + this._getTimeElapsedSinceLastStart(); } // 修改reset方法,重置回初始时间 reset() { this.overallTime = this.initialTime; if (this.isRunning) { this.startTime = Date.now(); return; } this.startTime = 0; } getTime() { if (!this.startTime) { return this.overallTime; // 初始状态返回设置的初始时间 } if (this.isRunning) { return this.overallTime + this._getTimeElapsedSinceLastStart(); } return this.overallTime; } } let the_interval; // 记录上一次输出的累计值,避免重复输出 let lastAccValue; function round_nearest_hundred(num) { return Math.round(num / 100) * 100; } function onUpdateTimer(duration) { const currentTime = timer.getTime(); const timeInSeconds = Math.round(currentTime / 1000); const currentAccValue = round_nearest_hundred(currentTime); // 更新秒数显示 document.getElementById('time').innerText = timeInSeconds; // 只有当当前值大于上一次输出值,且不超过目标时长时才更新 if (currentAccValue > lastAccValue && currentAccValue <= duration) { document.getElementById('accTime').innerText = currentAccValue; console.log(currentAccValue); lastAccValue = currentAccValue; } // 检查是否到达目标时长 if (currentAccValue >= duration) { document.getElementById('status').innerText = 'complete'; timer.stop(); timer_manager(false); // 最后更新一次目标值,避免遗漏 document.getElementById('accTime').innerText = duration; } } function timer_manager(flag, updateFunction, time, duration) { if (flag) { the_interval = setInterval(function() { updateFunction(duration); }, time); } else { clearInterval(the_interval); } } // 初始化定时器,设置初始值为400(这里可以改成你需要的任意初始值) const initialTimerValue = 400; const timer = new Timer(initialTimerValue); lastAccValue = initialTimerValue; // 初始化上一次输出值 // 初始化显示初始值 document.getElementById('accTime').innerText = initialTimerValue; timer_manager(true, onUpdateTimer, 50, 10000); document.getElementById('start').addEventListener('click', function() { timer.start(); }); document.getElementById('stop').addEventListener('click', function() { timer.stop(); }); document.getElementById('restart').addEventListener('click', function() { timer_manager(true, onUpdateTimer, 50, 10000); timer.reset(); timer.start(); // 重启后重置lastAccValue和状态 lastAccValue = initialTimerValue; document.getElementById('accTime').innerText = initialTimerValue; document.getElementById('status').innerText = ''; });
HTML部分(无需修改)
<p>Elapsed time: <span id="time">0</span>s</p> <p id="accTime"></p> <p id="status"></p> <button id="start">start</button> <button id="stop">pause</button> <button id="restart">restart</button>
关键修改点说明
Timer类支持初始时间:
- 构造函数新增
initialTime参数,默认0,初始化时将overallTime设为该值,并保存initialTime用于重置。 - 修改
getTime方法,初始状态(未启动时)返回设置的初始时间,确保页面加载时显示正确的初始值。 - 修改
reset方法,重置时将overallTime恢复到initialTime,符合“从指定值开始”的需求。
- 构造函数新增
避免重复/跳数输出:
- 新增
lastAccValue变量,记录上一次输出的100刻度值。 - 在
onUpdateTimer中,只有当currentAccValue大于lastAccValue时才更新DOM和控制台输出,确保每个100刻度只输出一次。 - 到达目标时长时,强制更新一次目标值,避免最后一步可能的遗漏。
- 新增
初始化与重启逻辑优化:
- 页面加载时直接设置
accTime的初始值,避免显示空白。 - 重启按钮点击时,重置
lastAccValue和状态文本,确保重启后回到初始状态。
- 页面加载时直接设置
这样修改后,定时器就能稳定输出100、200、300...直到10000,不会重复或跳数,并且可以从你指定的任意初始值(比如示例中的400)开始计数。
内容的提问来源于stack exchange,提问作者toddash
相关产品推荐
相关产品推荐

