5月27日 01:05
JavaScript 定时器为什么是不精确的?
setTimeout 和 setInterval 的执行时间不是精确的,根本原因就一条:JavaScript 是单线程的,定时器回调必须等主线程空闲才能执行。
比如你设置 setTimeout(fn, 10),但此时主线程有个耗时 100ms 的计算任务在执行——fn 最早也要等 100ms 后才能跑,10ms 只是"最早执行时间",不是"准时执行时间"。
其他影响因素:
- 浏览器最小延迟:嵌套 5 次以上的
setTimeout强制最小 4ms 间隔,后台标签页可能被降低到 1000ms - 事件循环优先级:微任务(Promise)比宏任务(定时器)优先执行
- GC 暂停:垃圾回收会短暂阻塞主线程
追问
需要精确计时怎么办?
- 短时间精度:用
performance.now()获取微秒级时间戳,自己在requestAnimationFrame里判断时间 - 长时间精度:用
Web Worker(独立线程,不会被主线程阻塞),Worker 里用setTimeout相对更准 - 音频场景:用
AudioContext.currentTime,这个不受主线程影响
requestAnimationFrame 比 setInterval 更精确吗?
rAF 本身也不是计时工具——它是"在浏览器下一次重绘前执行",频率取决于刷新率(60Hz 约 16.67ms)。它的优势是自动与渲染同步,不会做无效的更新。但作为定时器,它也有偏差。