实现一个比较精准的倒计时?

·  阅读 1363

首先 了解下 setTimeout的浅层原理,setTimeout 是通过浏览器异步API执行,执行完成之后,回调交给宏任务,假设宏任务队列已经有其他任务,就会导致 setTimeout 回调执行延后,从而不精准。

浏览器1s执行60帧,大概两帧之间的执行时间差为16ms,认为这样是比较好的体验。

requestAnimationFrame 是不需要设定时间,大概16ms执行一次。所以使用requestAnimationFrame 会更准确

<!--使用requestAnimationFrame 实现setInterval -->
export function mySetInterval(cb, cancelCb) {
  let timer = null;
  let pre = new Date()
  let fn = function() {
    timer = requestAnimationFrame(() => {
      let cur = new Date()
      if (cur - pre >= 1000) {
        cb()
        pre = cur
      }
      timer = requestAnimationFrame(fn)
      if (cancelCb && cancelCb()) {
        timer && cancelAnimationFrame(timer)
      }
    })
  }
  fn()
}

<!-- 倒计时 -->
export default class Countdown {
  constructor({ endTime }) {
    this.endTimetamp = new Date(endTime).getTime()
    console.log(endTime, this.endTimetamp);
    this.countDownDate = {}
    mySetInterval(this.countDown.bind(this), this.cancel.bind(this))
  }

  countDown() {
    let dis = (this.endTimetamp - new Date().getTime()) / 1000
    this.countDownDate = this.calculator(dis)
    console.log('发送事件---->', this.countDownDate);
    // this.on('countdown', this.countDownDate)
  }

  cancel() {
    return this.countDownDate && this.countDownDate.timetamp <= 0 ? true : false
  }
  
  calculator(second) {
    let sec = 1,
        min = 60 * sec,
        hour = 60 * min,
        day = 24 * hour;
    return {
        day: parseInt(second / day),
        hour: parseInt(second % day / hour),
        min: parseInt(second % hour / min),
        second: parseInt(second % min),
        timetamp: second
    }
  } 
}

export default Countdown

new Countdown({
    endTime: '2021-11-30 12:00'
})

复制代码

优点:

  1. 执行准时
  2. 与组件逻辑解藕
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改