一、背景
要实现一个倒计时页面,如下图:
服务端会下发瓜分结束时间awardEndTime,服务端当前时间timeStamp,前端需要计算出来时间差,并展示在页面中。
二、失败案例
在页面初始化的时候拿到awardEndTime和timeStamp,两者的差值得到倒计时所剩时间,用setInterval进行倒计时。
useEffect(() => {
let endCountDown = awardEndTime - timeStamp
countDown( Math.floor(endCountDown/1000))
}, [])
const CountDown = (maxtime) => {
timer = setInterval(() => {
if (maxtime > 0) {
--maxtime
let min = Math.floor(maxtime/60)
let sec = Math.floor(maxtime%60)
...
} else {
clearInterval(timer);
}
}, 1000)
}
自测阶段,在一部手机上没有发现倒计时有问题,两部手机一起测试的时候发现问题了,其中一部手机显示倒计时还剩2分钟,而另一部手机显示倒计时还有5分钟,明显出bug了。查找bug的时候发现,将倒计时页面退到后台,此时倒计时就不再执行了,导致重新回到页面的倒计时是从退出的时刻计时开始计算的。
三、问题解决
直接上代码
useEffect(() => {
let timeGap = timeStamp > 0 ? new Date().getTime() - timeStamp : 0;
CountDownNew(awardEndTime, timeGap)
}, [])
const CountDownNew = (endTime, timeGap) => {
timer = setInterval(() => {
let startTime = new Date().getTime() - timeGap;
let maxtime = Math.floor((endTime - startTime) / 1000);
if (maxtime > 0) {
--maxtime
let min = Math.floor(maxtime/60)
let sec = Math.floor(maxtime%60)
...
} else {
clearInterval(timer);
}
}, 1000)
}
问题轻松解决~
四、总结
1、失败原因
页面首次加载的时候,从接口拿到了首次加载的服务端时间和倒计时结束时间,并对时间差倒计时,当手机退到后台,再从后台回来时,不会重新请求接口去拿最新的服务端的当前时间,还是用过期的服务端时间,倒计时肯定不准确了。
2、优化思路
整体思路是每次倒计时都对当前时间做校准,得到最新的时间差。因为拿不到服务端的当前时间,所以要用客户端的时间表示服务端时间。每部手机的客户端时间展示可能会不同,但是他们和服务端时间的差值是固定的,在初始化的时候拿到两者的差值timeStamp,后面倒计时的时候用客户端的时间去校准服务端的时间就可以了。