秒杀倒计时(准确计时)

最近在准备事件循环的分享时,对于如何实现准确的计时有了点兴趣,因为在浏览器中,setTimeout/setInterval 并不是一个准确的计时,是存在延迟的。那么思考我们在双十一抢东西的场景,他们是如何做倒计时的呢?

方案1

确认服务端与客户端的时间差

  1. 首先,时间肯定是按服务器的时间 serverTime 为主,客户端通过通过请求接口获取服务端的时间。
    运营取设置开始时间 startTime
  2. 运营需要设置startTime,通过startTimeserverTime相减即为活动在各个手机上的真实的剩余时间。
  3. 因为前端在进行 setTimeoutsetInterval 时,会有时间的偏差,所以需要在该阶段消除误差。可以在执行新的 setTimeout 时将误差考虑进去,进行提前执行(一般都是1000ms更新一次)
    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
    //继续线程占用
    setInterval(function(){
    var j = 0;
    while(j++ < 100000000);
    }, 0);

    //倒计时
    var interval = 1000,
    ms = 50000, //从服务器和活动开始时间计算出的时间差,这里测试用50000ms
    count = 0,
    startTime = new Date().getTime();
    if( ms >= 0){
    var timeCounter = setTimeout(countDownStart,interval);
    }

    function countDownStart(){
    count++;
    var offset = new Date().getTime() - (startTime + count * interval);
    var nextTime = interval - offset;
    var daytohour = 0;
    if (nextTime < 0) { nextTime = 0 };
    ms -= interval;
    console.log("误差:" + offset + "ms,下一次执行:" + nextTime + "ms后,离活动开始还有:" + ms + "ms");
    if(ms < 0){
    clearTimeout(timeCounter);
    }else{
    timeCounter = setTimeout(countDownStart,nextTime);
    }
    }

    当阻塞过长的时候,需要另外处理。

方案2

使用requestAnimationFrame
每16.7ms执行一次,但是也会存在不准确的情况
本质上是将函数作为requestAnimationFrame的回调去执行以实现计时效果(函数内部继续执行requestAnimationFrame,并将函数自己传入)

方案3

使用webWorker
利用worker去处理计时,思路和方案1类似。

作者

徐云飞

发布于

2023-02-05

更新于

2023-02-05

许可协议

评论