JS 中也可以通过 new Date() 获取时间,但是获取的是客户端时间,这个事件客户端可以任意修改。
所以在项目中,如果时间作为重要参考标准,需要使用服务器时间。
思路:
向服务器发送一个请求
通过服务器返回的响应头获取到服务器时间
对获取的时间进行处理
将时间保存为全局变量
每过 1s,这个全局时间累加 1s,然后根据这个全局时间进行倒计时,避免一直发送请求
关于 new Date()
new Date() 获取当前客户端本机时间(是标准的事件格式数据 => 对象)
new Date(TimeStr) 把指定的时间字符串转换为标准时间数据,时间字符串支持很多格式,例如:YYYY-MM-DD HH:MM:SS、YYYY/MM/DD
两个 Date 实例相减得到的是时间相差的毫秒差
实现
解决时差
由于服务器端返回数据需要时间,所以客户端拿到返回的时间时,与现在的时间会存在一定误差,这个误差只能让其变小,无法彻底解决。
解决方案:
(1)在 Ajax 状态码为 2 的时候,即接受到响应头的时候,就可以从中获取信息,而不是等到更靠后的状态
(2)把请求方式直接设置为 head,只获取请求头信息即可,响应主体内容不需要
【特别的】即使我们向服务器发送一个不存在的请求地址,返回的是 404 状态码,但是响应头信息中都会存在服务器时间(不建议使用,产生 404 请求不友好)
解决持续请求
一个客户端每间隔 1 秒都会向服务器发送一个新的请求,如果访问用户增多,服务器压力就非常大,很容易瘫痪(负载均衡)
解决方案:
只在页面打开的时候,获取服务器时间
将获取的时间存储为全局变量
每一秒刷新的时候,都将其在原来的基础上一直累加,而不是重新从服务器获取最新时间
代码
let oTime = document.querySelector('.time'),oTimeSpan = oTime.querySelector('span'),autoTimer = null,nowTime = null;//=> 从服务器端获取时间let queryTime = function queryTime() {return new Promise(reslove => {//=> 向服务器发请求,把结果存储起来let xhr = new XMLHttpRequest();xhr.open('head', 'date.json');xhr.onreadystatechange = () => {if (xhr.readyState === 2 && /^(2|3)\d{2}$/.test(xhr.status)) {nowTime = new Date(xhr.getResponseHeader('date'));reslove();}};xhr.send(null);});}// 计算时间let computedTime = function computedTime() {let tarTime = new Date('2018-09-21 22:00:00'),diffTime = tarTime - nowTime;if (diffTime >= 0) {let hours = Math.floor(diffTime / 3600000);diffTime = diffTime - hours * 3600000;let minutes = Math.floor(diffTime / 60000);diffTime = diffTime - minutes * 60000;let seconds = Math.floor(diffTime / 1000);hours < 10 ? hours = '0' + hours : null;minutes < 10 ? minutes = '0' + minutes : null;seconds < 10 ? seconds = '0' + seconds : null;oTimeSpan.innerHTML = `${hours} : ${minutes} : ${seconds}`;nowTime = new Date(nowTime.getTime() + 1000);return;}oTimeSpan.innerHTML = '开始抢购!!';clearInterval(autoTimer);}let promise = queryTime();promise.then(computedTime);autoTimer = setInterval(computedTime, 1000);
