Web Worker 封装高精度计时器的核心是准确感知并补偿后台节流,而非避免暂停;通过 Page Visibility API 检测、动态维护 baseTime 与 pausedDuration、高频轮询+时间戳比对、定期时钟校准,结合 worker-timers 库实现稳定 100ms 级精度。

直接用 Web Worker 封装高精度计时器,核心不是“让定时器不停”,而是“准确知道它停了多久,并在恢复时补上节奏”。浏览器对后台标签页的定时器节流(如 setInterval 被压到 1 秒以上)是主动设计,无法绕过,但可被感知和补偿。
为什么主线程定时器不可靠
Chrome、Firefox 等现代浏览器在标签页失焦后,会强制将 setTimeout/setInterval 的最小间隔拉长至约 1000ms,甚至更慢。这不是 bug,而是为节省资源做的策略性节流。即使你设的是 100ms,实际执行可能严重滞后或堆积。更关键的是:主线程还受 JS 执行阻塞、渲染帧竞争、垃圾回收等干扰,天然不具备时间确定性。
Web Worker 是唯一可控的时间载体
Worker 线程虽也受节流影响,但它不依赖页面可见性,且能独立维护逻辑时钟。真正起作用的是组合策略:
- 主线程监听 Page Visibility API,检测 document.hidden 变化,通过 postMessage 主动通知 Worker 暂停/恢复
- Worker 内部维护 baseTime(初始参考点) + pausedDuration(累计挂起时长),所有触发时刻都基于此动态计算
- 不用 setInterval,改用高频轮询(如 setTimeout(..., 50))+ 时间戳比对:每次检查
Date.now() >= baseTime + interval * count + pausedDuration,满足才执行并递增 count
必须做时间同步校准
纯本地推算会随时间漂移,尤其经历长时间后台后误差明显。推荐每 30 秒左右由主线程向 Worker 发送一次同步消息:{ type: 'sync', serverTime: xxx, localTime: Date.now() }。Worker 根据往返延迟估算时钟偏差,修正 baseTime 偏移量。对倒计时类场景,也可直接同步剩余毫秒数,避免推算链过长。
优先使用 worker-timers 库
自己实现易出错,而 worker-timers 已封装全部关键逻辑:visibility 感知、暂停累计、自动校准、ID 管理、API 兼容。安装后即可替换原生调用:
import { setInterval, clearInterval } from 'worker-timers';
const id = setInterval(() => { /* 每100ms精准执行 */ }, 100);
实测表明,它能在后台标签页中稳定维持 100ms 级精度,无跳变、无任务堆积——这才是生产环境该有的表现。

















