当前位置:   article > 正文

使用setInterval执行定时器造成的倒计时误差问题修改_setinterval 倒计时差几秒

setinterval 倒计时差几秒

前言

最近在做微信小程序直播间秒杀抢券的功能,功能完成提测后,测试过来说这倒计时不对呀,在不同手机上倒计时有误差。听到反馈,第一反应就是又要掉头发了。于是,当即开始查找资料,定位问题,解决后,写此文章做个记录。

注意:用来计算倒计时的当前时间,不可以取用户客户端的时间(因为客户端时间用户可以随时调整,会造成时间不一致),应该是取后端返回的服务器的时间。

1、最初使用setInterval执行倒计时定时器,由于javascript是单线程的,同一时间只能执行一个js代码(同一时间其他异步事件执行会被阻塞 ) ,导致定时器事件每次执行都会有时间误差,甚至误差会越来越大。
最初代码如下:

Page({
  /**
   * 页面的初始数据
   */
  data: {
    timer: null, // 定时器
    countdownEndTime: '', // 倒计时结束时间 即开始时间
    countdownTime: '抢', // 倒计时显示
  },

  // 倒计时
  countTime: function () {
    var that = this;
    let countDownNum = that.getCountdownTime(); //获取倒计时初始值
    if (countDownNum <= 0) return;
    var string = that.getCountdownString(countDownNum);
    that.setData({
      countdownTime: string
    });

    var interval = 1000
    that.data.timer = setInterval(function() {
      countDownNum -= interval;
      var string = that.getCountdownString(countDownNum);
      if (countDownNum <= 0) {
        clearInterval(that.data.timer);
      } else {
        that.setData({
          countdownTime: string
        })
      }
    }, interval)
  },

  getCountdownString: function (time) {
    var m = Math.floor(time / 1000 / 60 % 60);
    var s = Math.floor(time / 1000 % 60);
    if (m <= 0 && s<= 10) {
      return s;
    }
    s = s < 10 ? "0" + s : s;
    m = m < 10 ? "0" + m : m;
    var string = `${m}:${s}`;
    return string;
  },

  getCountdownTime: function () {
    var that = this;
    var time = that.data.countdownEndTime - that.data.dataTimestamp;
    return time;
  }
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

2、首先我们来看一个定时器执行时间测试:

var start = new Date().getTime(), count = 0
setInterval(function () {
  count++
  console.log(new Date().getTime() - (start + count * 1000) + 'ms')
}, 1000)
  • 1
  • 2
  • 3
  • 4
  • 5

目测代码运行结果,定时器每秒执行一次,每次输出应该是0,但结果并非如此,实际输出如下:
在这里插入图片描述
结论:由于代码执行占用时间和其他事件阻塞原因,导致定时器事件执行延迟了几ms,但影响较小。

加下来加一段阻塞线程的代码,再次测试:

// 占用线程事件
setInterval(function () {
  var n = 0
  while (n++ < 1000000000);
}, 1000)

var start = new Date().getTime(), count = 0
setInterval(function () {
  count++
  console.log(new Date().getTime() - (start + count * 1000) + 'ms')
}, 1000)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

执行结果输出如下:
在这里插入图片描述

结论:由于加了很占线程的阻塞事件,导致定时器事件每次执行延迟越来越严重。

由于实际项目中,执行计时器的同时,会有很多其他异步阻塞事件,会导致倒计时功能不精确。

3、解决方案

通过引入计数器,判断计时器延迟执行的时间来进行误差修正,尽量让误差缩小,不同浏览器不同时间段打开页面倒计时误差可控制在1s以内。

最终代码修改为setTimeout:

// 倒计时
 countTime: function () {
   var that = this;
   let countDownNum = that.getCountdownTime(); //获取倒计时初始值
   if (countDownNum <= 0) return;
   var string = that.getCountdownString(countDownNum);
   that.setData({
     countdownTime: string
   });
   var interval = 1000, start = new Date().getTime(), count = 0;
   that.data.timer = setTimeout(countDownStart, interval);
   function countDownStart() {
     var offset, nextTime; // offset是倒计时误差时间,nextTime是减去误差时间后下一次执行的时间
     count++;
     offset = new Date().getTime() - (start + count * interval);
     nextTime = interval - offset;
     if (nextTime < 0) { nextTime = 0; }
     countDownNum -= interval;
     var string = that.getCountdownString(countDownNum);
     console.log("误差: " + offset + "ms, 下一次执行: " + nextTime + "ms后,离活动开始还有: " + countDownNum + "ms");
     if (countDownNum <= 0) {
       clearTimeout(that.data.timer);
     } else {
       that.setData({
         countdownTime: string
       })
       that.data.timer = setTimeout(countDownStart, nextTime);
     }
   }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

运行结果如下:
在这里插入图片描述

参考文章:https://www.jianshu.com/p/24895fdba736

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/128882
推荐阅读
相关标签
  

闽ICP备14008679号