考试JS倒计时客户端和服务器时间同步问题
需求实现考试时间页面倒计时。
这个需求以前在刀具大赛的时候也遇到过,当时是使用前端每秒定时请求后台返回倒计时时间。这样的缺点就是当用户量大的时候,会有的大量的请求造成性能下降(其实用户少或者使用场景少的时候也没啥事),优点就是时间比较准确,没有浏览器的兼容问题。
还有一种解决方案就是第一次请求的时候返回时间,然后就在客户端倒计时就好(当然为了防止客户端改时间作弊,提交请求的时间要在服务器端检查)。这种做的优点服务端没有请求的压力,实现起来也比较简单。
一、存在问题的实现方式:
复制粘贴拿起键盘,啪啪啪 倒计时代码就好了
1 | var time = 60;//服务端返回的剩余时间 |
存在的问题:你这东西不准啊,我看着几分钟,有好几秒的延迟
其实是setTimeout/setInterval误差的问题,我们可通过减少误差,通过对下一次任务的调用时间进行修正。
代码如下:
1 | let count = 0; |
存在的问题:你这东西有问题啊,浏览器切换网页后,在回来看页面,这段过程是暂停的,延迟了几分钟 没考虑浏览器的”休眠”,浏览器切换回来,倒计时是暂停的
综上所述:
浏览器中的定时器任务是有误差的,也就是我们常说的 setTimeout 为什么不准的问题,这里涉及到 js 单线程以及运行机制,具体运行原理可参考 2019-11-04-JS倒计时setTimeout为什么会出现误差。
二、优化后的实现方式:
即使利用setTimeout()模拟setInterval(),还是会因为其余脚本的执行,造成误差。所以,我认为JS定时函数setInterval、setTimeout的弊端无法避免,只能通过多次与服务器沟通,来矫正时间。
封装后的countDown.js
1 | (function () { |
使用方法
首先要引入countDown.js
1 | //倒计时10秒 |
经测试通过服务器时间校准,可以避免时间不准的问题而且还大大减轻了服务器端的压力。即使浏览器切到后台运行,倒计时停止也没有关系。
参考文档:
https://segmentfault.com/q/1010000000698541/a-1020000000698620