Skip to content
本页目录

定时器

介绍

定时器并不是 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,则设置 timeout4ms

实际情况各个浏览器厂商并未严格遵循,例如 chrome 浏览器中,低于 5 层时最小间隔是 1ms,高于 5 层时是 5ms,测试日志结果如下:[1, 1, 1, 1, 5, 10, 15, 20]

注意事项:

  • 使用定时器,一定要在页面卸载前移除定时器
  • this 指向问题,建议使用箭头函数解决

为什么定时器时间不准

浏览器为了防止真正 0 秒执行造成队列堵死,会以最小间隔 1ms 才会触发,触发后会放入到队列中等待同步代码与微任务执行完毕才执行(详细请查看任务队列),所以造成定时器执行时间肯定比设置时间要长。

扩展:之前在项目中做过考试倒计时功能,会存在 3 个问题:

  1. 获取的是本地时间,如果修改设备时间会导致不准确;
  2. 定时器时间不准确,因为每秒都会存在延时,累计起来就会很多;
  3. 用户从页面窗口离开(切换到桌面或其它 App),导致定时器停止工作;

解决方案是:后端提供个接口获取当前的准确时间,定时器每隔一段时间(比如5分钟)后再次调用该接口修正时间。从窗口离开与进入会触发 visibilitychange 事件,当监听到其进入时,调用接口修正时间。