JS精确倒计时实现

需求:

目前app需要做一个VIP抢购功能,提到抢购功能前端必不可少倒计时

踩坑:

用户吐槽如果手机保持打开倒计时页面长时间不动,两个不同的手机因为时间过长会产生过大的差异,导致一些用户倒计时显示还没结束实际上已经被抢购完了。

原因:
  1. 前端不应该采用客户端时间来计时,要根据服务器返回的时间进行判断
  2. 没有考虑js冻结运行耗费时间;(移动端下滑页面的倒计时不动,目前app没有涉及)
  3. js计时器线程堵塞,导致计时器每次都有延迟
计时器原理:

提到计时器肯定少不了setTimeout或setInterval这两个函数,前端大牛John.Resig (jQuery作者) 很好的讲解了JavaScript解释器工作原理

我的大概理解:
  • js属于单线程执行,同一时间只能执行一个js代码,同一时间的其他异步程序会被堵塞,当异步事件发生时,它会进入代码的执行队列,执行线程空闲时按照顺序依次执行。
  • 当定时器触发了但是它不会立即执行,会把需要执行的函数放入队列里面,等到执行线程空闲时再去执行。因此在执行线程繁忙的时间可能照成微小的误差,时间长了就会出现两个用户计时差距过大的问题。
单个定时器执行误差:
1
2
3
4
5
误差:96ms,下一次执行:904ms后,离活动开始还有:17968s 
误差:95ms,下一次执行:905ms后,离活动开始还有:17967s
误差:97ms,下一次执行:903ms后,离活动开始还有:17966s
误差:95ms,下一次执行:905ms后,离活动开始还有:17965s
误差:95ms,下一次执行:905ms后,离活动开始还有:17964s
解决方案:
1.写一个周期性定时期,每隔一分钟向服务器发送一次请求来修正倒计时。弊端:会增大服务器压力,同一时间服务器的请求次数变多;每次修正的时候会出现跳秒现象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
setInterval( () => {
this.count++;
console.log('这是我第' + this.count + '次执行');
this.$http.post('/url', {}, {
params:{
userId:*****
},
custom:{
*****
}
}).then( res => {
this.** = Number(res.data.data.**).toFixed(4) ;
this.** = res.data.data.**.toString();
this.** = res.data.data.**;
this.** = Number(res.data.data.**);
this.** = res.data.data.**;
})
},60000);
2.进入页面存一下进入页面的毫秒数,用变量count记一下计时器执行的次数
  1. 执行误差:(最新执行时间 - (进入页面的毫秒数 + count * 1000ms));
  2. 定时器执行时间(每隔多少秒执行一次计时器):1000ms - 误差时间 (如果执行时间小于0 要赋值为0);
  3. 倒计时-1;
  4. 当倒计时小于0就清除定时器,否则就再次执行定时器这里定时器执行的时间取决于步骤2计算出来的!
1
2
3
4
5
6
7
8
9
10
11
12
13
jsq:function(){
this.count++;
let offset = new Date().getTime() - (this.startTime + this.count * this.interval);
this.nextTime = this.interval - offset;
if(this.nextTime < 0) { this.nextTime = 0};
this.ms -= this.interval;
console.log("误差:" + offset + "ms,下一次执行:" + this.nextTime + "ms后,离活动开始还有:" + this.ms + "ms");
if(this.ms < 0){
clearTimeout(timeCounter);
} else {
let timeCounter = setTimeout(this.jsq,this.nextTime);
}
}
运行结果:
1
2
3
4
5
误差:96ms,下一次执行:904ms后,离活动开始还有:17968s 
误差:95ms,下一次执行:905ms后,离活动开始还有:17967s
误差:97ms,下一次执行:903ms后,离活动开始还有:17966s
误差:95ms,下一次执行:905ms后,离活动开始还有:17965s
误差:95ms,下一次执行:905ms后,离活动开始还有:17964s

以上全部是个人理解,如果差错请指正。谢谢

友情链接:
查看评论