定时器
介绍
定时器并不是 ECMAScript
标准的内容,它是各个浏览器厂商的实现,所以它属于 BOM
范畴。 HTML5
标准规定了定时器的具体行为。
以下以 setTimeout
为例: 语法:
JS
// timerId 定时器编号, clearTimeout() 通过这个 ID 移除定时器
// delay 默认值为 0,可以省略
const timerId = setTimeout(() => {
}, delay)
// timerId 定时器编号, clearTimeout() 通过这个 ID 移除定时器
// delay 默认值为 0,可以省略
const timerId = setTimeout(() => {
}, delay)
标准中规定:
如果定时器嵌套的层级超过了
5
层,并且timeout
小于4ms
,则设置timeout
为4ms
。
实际情况各个浏览器厂商并未严格遵循,例如 chrome
浏览器中,低于 5
层时最小间隔是 1ms
,高于 5
层时是 5ms
,测试日志结果如下:[1, 1, 1, 1, 5, 10, 15, 20]
注意事项:
- 使用定时器,一定要在页面卸载前移除定时器
this
指向问题,建议使用箭头函数解决
为什么定时器时间不准
浏览器为了防止真正 0
秒执行造成队列堵死,会以最小间隔 1ms
才会触发,触发后会放入到队列中等待同步代码与微任务执行完毕才执行(详细请查看任务队列),所以造成定时器执行时间肯定比设置时间要长。
扩展:之前在项目中做过考试倒计时功能,会存在 3
个问题:
- 获取的是本地时间,如果修改设备时间会导致不准确;
- 定时器时间不准确,因为每秒都会存在延时,累计起来就会很多;
- 用户从页面窗口离开(切换到桌面或其它 App),导致定时器停止工作;
解决方案是:后端提供个接口获取当前的准确时间,定时器每隔一段时间(比如5分钟)后再次调用该接口修正时间。从窗口离开与进入会触发 visibilitychange
事件,当监听到其进入时,调用接口修正时间。