zoukankan      html  css  js  c++  java
  • 使用 requestAnimationFrame 实现定时器,解决 setInterval 执行次数丢失问题

    来看这样一个场景:使用 setInterval 定时器倒计时,突然来了一个长达三秒的任务,定时器会有一次不准,两次丢失回调,导致少两次计算时间。

    // 在控制台上输入下面四行
    var second = 0
    setInterval(function() {
      console.log(`setInterval ${++second}`, new Date().getTime())
    }, 1000)
    
    // 几秒之后输入下面代码
    function sleep(ms) {
      const end = new Date().getTime() + ms
      console.log('sleep start')
      while (new Date().getTime() < end) {}
      console.log('sleep end')
    }
    sleep(3000)
    

    如图所示,少两次回调的执行。


    requestAnimationFrame 实现定时器

    requestAnimationFrame 传入一个回调函数,该回调函数会在浏览器下一次重绘之前执行,详情查看MDN文档 window.requestAnimationFrame

    /**
     * 设置精度定时器
     * @param {function} 回调函数
     * @param {number}   延迟时间
     * @return {number}  定时器ID
     */
    function setIntervalPrecision(callback, delay) {
      // 生成并记录定时器ID
      let obj = window.interValPrecisionObj || (window.interValPrecisionObj = { num: 0 })
      obj.num++
      obj['n' + obj.num] = true
      var intervalId = obj.num
      // 开始时间
      var startTime = +new Date()
      // 已执行次数
      var count = 0
      // 延迟时间
      delay = delay || 0
    
    
      ;(function loop() {
        // 定时器被清除,则终止
        if (!obj['n' + intervalId]) return
    
        // 满足条件执行回调
        if (+new Date() > startTime + delay * (count + 1)) {
          count++
          callback(count)
        }
    
        requestAnimationFrame(loop)
      })()
    
      return intervalId
    }
    
    /**
     * 清除精度定时器
     * @param {number} 定时器ID
     */
    function clearIntervalPrecision(intervalId) {
      if (window.interValPrecisionObj) {
        delete window.interValPrecisionObj['n' + intervalId]
      }
    }
    

    测试

    // 在控制台上输入下面四行
    setIntervalPrecision(function(val) {
      console.log(`setIntervalPrecision ${val}`, new Date().getTime())
    }, 1000)
    
    // 几秒之后输入下面代码
    function sleep(ms) {
      const end = new Date().getTime() + ms
      console.log('sleep start')
      while (new Date().getTime() < end) {}
      console.log('sleep end')
    }
    sleep(3000)
    

    任务阻塞结束后,会瞬间执行阻塞期间需要执行次数的回调,虽然倒计时页面会卡三秒(js特性),但实际剩余秒数不会出错。


    whosmeya.com

  • 相关阅读:
    css 和 svg 实现蚂蚁行军效果
    ASP.NET Core使用Swagger实现接口文档并分组
    Centos7+DockerCompose部署ASP.NET Core3.1应用
    Centos7+Docker部署ASP.NET Core3.1应用
    ASP.NET Core下的Cache
    在asp.net web form项目中添加webapi接口
    windows服务中对外提供API接口
    ASP.NET Core使用log4net记录日志
    SSL踩坑ERR_SSL_VERSION_OR_CIPHER_MISMATCH
    C# 调用微信接口上传素材和发送图文消息
  • 原文地址:https://www.cnblogs.com/whosmeya/p/14135507.html
Copyright © 2011-2022 走看看