原因
- 浏览器中的所有JavaScript都在单线程上执行,所以异步事件(比如定时器)仅在线程空闲时才会被调度运行。
- 为了控制要执行的代码, JavaScript 配置了一个任务队列,这些异步事件任务会按照将它们添加到队列的顺序执行。
- 而setTimeout() 的第二个参数(延时时间)只是告诉 JavaScript 再过多长时间把当前任务添加到队列中。如果队列是空的,那么添加的代码会立即执行;如果队列不是空的,那么它就要等前面的代码执行完了以后再执行。
因此定时器延迟是不能保证的。
解决方案
动态计算时差 (仅针对循环定时,只起修正作用 )
- 在定时器开始前和运行时动态获取当前时间,在设置下一次定时时长时,在期望值基础上减去当前时延,以获得相对精准的定时运行效果。
- 此方法仅能消除setInterval()长时间运行造成的误差累计,但无法消除单个定时器执行延迟问题。
注: 时差过大时,由于无法时间回流,只能按没有间隔处理,减轻影响
1 | var startTime = new Date().getTime(); |
使用 Web Worker
Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。这样的好处是,一些计算密集型或高延迟的任务,被 Worker 线程负担了,主线程(通常负责 UI 交互)就会很流畅,不会被阻塞或拖慢。
1 | var startTime = new Date().getTime(); |
1 | // worker.js |