秒杀倒计时(准确计时)
最近在准备事件循环的分享时,对于如何实现准确的计时有了点兴趣,因为在浏览器中,setTimeout/setInterval 并不是一个准确的计时,是存在延迟的。那么思考我们在双十一抢东西的场景,他们是如何做倒计时的呢?
方案1
确认服务端与客户端的时间差
- 首先,时间肯定是按服务器的时间
serverTime
为主,客户端通过通过请求接口获取服务端的时间。
运营取设置开始时间 startTime - 运营需要设置
startTime
,通过startTime
与serverTime
相减即为活动在各个手机上的真实的剩余时间。 - 因为前端在进行
setTimeout
或setInterval
时,会有时间的偏差,所以需要在该阶段消除误差。可以在执行新的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类似。