Chrome扩展中chrome.alarms遇系统时间变更异常的修复咨询
问题描述
我正在使用chrome.alarm在Chrome扩展图标上显示倒计时,更新频率约为每秒一次。当前遇到的问题是:
- 手动调整系统时间向前,或电脑从睡眠状态唤醒时,计数器会开始高频更新(每秒多次)以追赶新的系统时间;
- 将系统时间向后调整,计时器则会停止运行。
希望修改代码,使计时器在系统时间变更时直接跳转至当前时间,恢复正常的每秒更新节奏。
测试用扩展代码如下:
manifest.json
{ "manifest_version": 3, "name": "Test timer", "author": "test", "description": "Test chrome.alarm", "version": "0.0.1", "permissions": [ "alarms" ], "action": {}, "background": { "service_worker": "service_worker.js" } }
service_worker.js(原代码)
let i = 0, start = new Date().getTime(), pad = (n,s=2) => ("0"+n).slice(-s), time = d => pad(d.getHours()) + ":" + pad(d.getMinutes()) + ":" + pad(d.getSeconds()) + "." + pad(d.getMilliseconds(),3); chrome.alarms.onAlarm.addListener(loop); console.log("started"); loop(); function loop() { const now = new Date().getTime(), //make sure timer doesn't drift from starting point next = now - ((now - start) % 1000); //repeat after 1sec chrome.alarms.create({ when: next + 1000 }); chrome.action.setBadgeText({text:"" + (i = ++i % 1000)}); console.log("Date:", time(new Date(now)), "alarm:", time(new Date(next))); }
问题根源
原代码依赖固定的初始start时间计算下一次闹钟触发点,当系统时间发生跳变(向前调、向后调、睡眠唤醒)时,now - start的差值不再反映实际流逝的时间:
- 系统时间向前跳:
now - start的差值突然变大,计算出的next会远小于当前now,导致chrome.alarms.create立刻触发闹钟,形成高频更新; - 系统时间向后跳:
next + 1000会落在当前now的过去,Chrome不会触发过去的闹钟,导致计时器停止。
解决方案
放弃依赖固定初始时间的逻辑,改为基于当前系统时间动态计算下一个整秒触发点,同时加入系统时间跳变的检测:每次触发闹钟时,对比当前时间与预期的触发时间,若差值超过合理阈值(比如1.5秒),判定为系统时间发生变化,直接重置计时逻辑,以当前时间为基准重新计算下一次触发点。
修改后的代码
service_worker.js
let i = 0; let lastScheduled = null; // 跟踪上一次预期的闹钟触发时间 const pad = (n, s = 2) => ("0" + n).slice(-s); const time = d => pad(d.getHours()) + ":" + pad(d.getMinutes()) + ":" + pad(d.getSeconds()) + "." + pad(d.getMilliseconds(), 3); chrome.alarms.onAlarm.addListener(loop); console.log("started"); loop(); function loop() { const now = new Date().getTime(); let nextTrigger; // 检测系统时间是否发生跳变 if (lastScheduled && Math.abs(now - lastScheduled) > 1500) { // 时间差超过1.5秒,判定为系统时间变更,重置为当前时间的下一个整秒 nextTrigger = now - (now % 1000) + 1000; } else { // 正常情况,计算下一个整秒触发点 nextTrigger = now - (now % 1000) + 1000; } // 更新跟踪的预期触发时间 lastScheduled = nextTrigger; // 创建下一次闹钟 chrome.alarms.create({ when: nextTrigger }); // 更新徽章计数(模拟倒计时/计数逻辑) i = (i + 1) % 1000; chrome.action.setBadgeText({ text: "" + i }); console.log("Date:", time(new Date(now)), "Next alarm:", time(new Date(nextTrigger))); }
代码说明
- 移除固定
start变量:改用lastScheduled跟踪上一次预期的闹钟触发时间,避免依赖初始时间; - 系统时间跳变检测:通过对比当前时间与
lastScheduled的差值,判断是否发生时间跳变,阈值设为1.5秒是为了兼容正常的闹钟触发误差; - 动态计算触发点:无论是否发生时间跳变,都基于当前系统时间计算下一个整秒点,确保计时器始终与当前系统时间同步;
- 重置计数逻辑:当检测到时间跳变时,直接以当前时间为基准重新开始,避免高频更新或停止的问题。
内容的提问来源于stack exchange,提问作者vanowm
相关产品推荐
相关产品推荐

