>[success] # 倒计时抢购案例 ~~~ 1.获取服务器时间可以从任意接口或者资源中的响应头Date 获取如图 ~~~ ![](https://img.kancloud.cn/20/7b/207bc5c496dae4b6f54491c171a4e330_516x111.png) ~~~ /* * 两个时间: * + 目标时间 18:00:00 * + 当前时间 * 目标时间-当前时间=时间差 「毫秒差:计算时间差中包含多少小时,多少分钟,多少秒」 * 每间隔一秒中都需要重新获取当前时间「定时器 setInterval」,重算时间差等 * * 核心的问题: * 当前时间是不可以获取客户端本地的(因为本地的时间客户自己可以肆意的修改),需要统一获取服务器的时间「响应头->Date」 * + 获取服务器时间会存在时间偏差问题 --> HEAD AJAX状态码为2 * * 在页面不刷新的情况下,每间隔1秒,不是再次从服务器获取(如果这样:服务器会崩溃,用户得到的时间误差也会越大...),而是基于第一次获取的结果之上,手动给其累加1000ms即可 */ let countdownModule = (function () { let textBox = document.querySelector('.text'), serverTime = 0, targetTime = +new Date('2020/12/05 16:00:00'), timer = null; // 获取服务器时间 const queryServerTime = function queryServerTime() { return new Promise(resolve => { let xhr = new XMLHttpRequest; xhr.open('HEAD', '/'); xhr.onreadystatechange = () => { if ((xhr.status >= 200 && xhr.status < 300) && xhr.readyState === 2) { let time = xhr.getResponseHeader('Date'); // 获取的时间是格林尼治时间 -> 变为北京时间 resolve(+new Date(time)); } }; xhr.send(null); }); }; // 倒计时计算 const supplyZero = function supplyZero(val) { val = +val || 0; return val < 10 ? `0${val}` : val; }; const computed = function computed() { let diff = targetTime - serverTime, hours = 0, minutes = 0, seconds = 0; if (diff <= 0) { // 到达抢购时间了 textBox.innerHTML = '00:00:00'; clearInterval(timer); return; } // 没到时间则计算即可 hours = Math.floor(diff / (1000 * 60 * 60)); diff = diff - hours * 1000 * 60 * 60; minutes = Math.floor(diff / (1000 * 60)); diff = diff - minutes * 1000 * 60; seconds = Math.floor(diff / 1000); textBox.innerHTML = `${supplyZero(hours)}:${supplyZero(minutes)}:${supplyZero(seconds)}`; }; return { async init() { serverTime = await queryServerTime(); computed(); // 设置定时器 timer = setInterval(() => { serverTime += 1000; computed(); }, 1000); } }; })(); countdownModule.init(); ~~~