Shaoli's Blog

用requestAnimationFrame来代替setInterval和setTimout

requestAnimationFrame的执行机制


目前的显示器大部分的PSF都是60帧/秒,即每1000/60 = 16.7ms刷新一次,如果setTimeout/setInterval设置的时间间隔小于16.7,那么就会出现过度绘制的问题。而requestAnimationFrame正是为了这个而出现的,它会跟着浏览器的绘制走,浏览器每次重绘会通知requestAnimationFrame:我要重绘了。所以如果浏览器的绘制间隔是16.7s,它就会每隔16.7s绘制一次,这就不存在过度绘制导致掉帧的问题。

  • 而且就算有多个requestAnimationFrame存在,浏览器会统一通知,而setTimeout是相互独立的,所以会耗费更多资源。
  • 当页面tab切换到其他页面时,requestAnimationFrame会停止运行,节约资源。(chrome浏览器对时间间隔小于1s的setInterval也)


/**
 * 用requestAnimationFrame替代setTimeout、setInterval,解决内存溢出
 * @export
 * @param {*} cb 定时回调
 * @param {*} interval 定时时间
 */
export const customizeTimer = {
  intervalTimer: null,
  timeoutTimer: null,
  setTimeout (cb, interval) {
    // 实现setTimeout功能
    const now = Date.now
    const stime = now()
    let etime = stime
    const loop = () => {
      this.timeoutTimer = requestAnimationFrame(loop)
      etime = now()
      if (etime - stime >= interval) {
        cb()
        cancelAnimationFrame(this.timeoutTimer)
      }
    }
    this.timeoutTimer = requestAnimationFrame(loop)
    return this.timeoutTimer
  },
  clearTimeout () {
    cancelAnimationFrame(this.timeoutTimer)
  },
  setInterval (cb, interval) {
    // 实现setInterval功能
    const now = Date.now
    let stime = now()
    let etime = stime
    const loop = () => {
      this.intervalTimer = requestAnimationFrame(loop)
      etime = now()
      if (etime - stime >= interval) {
        stime = now()
        etime = stime
        cb()
      }
    }
    this.intervalTimer = requestAnimationFrame(loop)
    return this.intervalTimer
  },
  clearInterval () {
    cancelAnimationFrame(this.intervalTimer)
  }
}


// 测试
let count = 0
const test = () => {
  console.log(count)
  count++
}
customizeTimer.setInterval(test, 1000)


    评论列表

  • 暂无评论...快来说说吧!
person
0 / 16
comment
0 / 100