js前端如何写一个精确的倒计时代码


Posted in Javascript onOctober 25, 2019

关于写倒计时大家可能都都比较熟悉,使用 setTimeout 或 setInterval 就可以搞定。几秒钟或者几分钟的倒计时这样写没有问题,但是如果是长时间的倒计时,这样写就会不准确。如果用户修改了他的设备时间,这样的倒计时就没有意义了。今天就说说写一个精确的倒计时的方法。

原理

众所周知 setTimeout 或者 setInterval 调用的时候会有微小的误差。有人做了一个 demo 来观察这个现象并对其做了修正。短时间的误差倒也可以接受,但是作为一个长时间的倒计时,误差累计就会导致倒计时不准确。

因此我们可以在获取剩余时间的时候,每次 new 一个设备时间,因为设备时间的流逝相对是准确的,并且如果设备打开了网络时间同步,也会解决这个问题。

但是,如果用户修改了设备时间,那么整个倒计时就没有意义了,用户只要将设备时间修改为倒计时的 endTime 就可以轻易看到倒计时结束是页面的变化。因此一开始获取服务端时间就是很重要的。

简单的说,一个简单的精确倒计时原理如下:

  • 初始化时请求一次服务器时间 serverTime,再 new 一个设备时间 deviceTime
  • deviceTime 与 serverTime 的差作为时间偏移修正
  • 每次递归时 new 一个系统时间,解决 setTimeout 不准确的问题

代码

获取剩余时间的代码如下:

/**
 * 获取剩余时间
 * @param {Number} endTime  截止时间
 * @param {Number} deviceTime 设备时间
 * @param {Number} serverTime 服务端时间
 * @return {Object}      剩余时间对象
 */
let getRemainTime = (endTime, deviceTime, serverTime) => {
  let t = endTime - Date.parse(new Date()) - serverTime + deviceTime
  let seconds = Math.floor((t / 1000) % 60)
  let minutes = Math.floor((t / 1000 / 60) % 60)
  let hours = Math.floor((t / (1000 * 60 * 60)) % 24)
  let days = Math.floor(t / (1000 * 60 * 60 * 24))
  return {
    'total': t,
    'days': days,
    'hours': hours,
    'minutes': minutes,
    'seconds': seconds
  }
}

获取服务器时间可以使用 mtop 接口 mtop.common.getTimestamp

然后可以通过下面的方式来使用:

// 获取服务端时间(获取服务端时间代码略)
getServerTime((serverTime) => {

  //设置定时器
  let intervalTimer = setInterval(() => {

    // 得到剩余时间
    let remainTime = getRemainTime(endTime, deviceTime, serverTime)

    // 倒计时到两个小时内
    if (remainTime.total <= 7200000 && remainTime.total > 0) {
      // do something

    //倒计时结束
    } else if (remainTime.total <= 0) {
      clearInterval(intervalTimer);
      // do something
    }
  }, 1000)
})

这样的的写法也可以做到准确倒计时,同时也比较简洁。不需要隔段时间再去同步一次服务端时间。

补充

在写倒计时的时候遇到了一个坑这里记录一下。

千万别在倒计时结束的时候请求接口。会让服务端瞬间 QPS 峰值达到非常高。

js前端如何写一个精确的倒计时代码

如果在倒计时结束的时候要使用新的数据渲染页面,正确的做法是:

在倒计时结束前的一段时间里,先请求好数据,倒计时结束后,再渲染页面。

关于倒计时,如果你有什么更好的解决方案,欢迎评论交流。

Javascript 相关文章推荐
又一个小巧的图片预加载类
May 05 Javascript
jquery 插件之仿“卓越亚马逊”首页弹出菜单效果
Dec 25 Javascript
网页整体变灰白色(兼容各浏览器)实例
Apr 21 Javascript
jquery live()重复绑定的解决方法介绍
Jan 03 Javascript
兼容主流浏览器的jQuery+CSS 实现遮罩层的简单代码
Oct 14 Javascript
javascript中定义类的方法详解
Feb 10 Javascript
js文本框走动跑马灯效果代码分享
Aug 25 Javascript
jQuery实现带延迟效果的滑动菜单代码
Sep 02 Javascript
easyUI combobox实现联动效果
Jan 17 Javascript
JavaScript实现模态对话框实例
Jan 13 Javascript
uniapp实现横向滚动选择日期
Oct 21 Javascript
JavaScript实现图片合成下载的示例
Nov 19 Javascript
对layui数据表格动态cols(字段)动态变化详解
Oct 25 #Javascript
layui实现数据表格隐藏列的示例
Oct 25 #Javascript
关于在LayUI中使用AJAX提交巨坑记录
Oct 25 #Javascript
浅谈layui 绑定form submit提交表单的注意事项
Oct 25 #Javascript
详解如何在Vue项目中发送jsonp请求
Oct 25 #Javascript
layui实现form表单同时提交数据和文件的代码
Oct 25 #Javascript
vue实现弹幕功能
Oct 25 #Javascript
You might like
php的urlencode()URL编码函数浅析
2011/08/09 PHP
PHP按行读取文件时删除换行符的3种方法
2014/05/04 PHP
jquery多选项卡效果实例代码(附效果图)
2013/03/23 Javascript
使用jquery选择器如何获取父级元素、同级元素、子元素
2014/05/14 Javascript
jQuery学习笔记之jQuery+CSS3的浏览器兼容性
2015/01/19 Javascript
javascript将异步校验表单改写为同步表单
2015/01/27 Javascript
jQuery同步提交示例代码
2015/12/12 Javascript
jQuery validate+artdialog+jquery form实现弹出表单思路详解
2016/04/18 Javascript
javascript完美实现给定日期返回上月日期的方法
2017/06/15 Javascript
[01:30:15]DOTA2-DPC中国联赛 正赛 Ehome vs Aster BO3 第二场 2月2日
2021/03/11 DOTA
Python实现在线程里运行scrapy的方法
2015/04/07 Python
python批量导入数据进Elasticsearch的实例
2018/05/30 Python
python计算阶乘和的方法(1!+2!+3!+...+n!)
2019/02/01 Python
python3+selenium自动化测试框架详解
2019/03/17 Python
Python企业编码生成系统总体系统设计概述
2019/07/26 Python
Python数组拼接np.concatenate实现过程
2020/04/18 Python
python 使用raw socket进行TCP SYN扫描实例
2020/05/05 Python
django为Form生成的label标签添加class方式
2020/05/20 Python
python删除指定列或多列单个或多个内容实例
2020/06/28 Python
python类共享变量操作
2020/09/03 Python
如何利用Python matplotlib绘制雷达图
2020/12/21 Python
英国领先的在线旅游和休闲零售商:lastminute.com
2019/01/23 全球购物
上班迟到检讨书
2014/01/10 职场文书
蛋糕店创业计划书
2014/05/06 职场文书
2014年教师节讲话稿5篇
2014/09/10 职场文书
2014年店长工作总结
2014/11/17 职场文书
2014年英语教研组工作总结
2014/12/06 职场文书
公务员考察材料
2014/12/23 职场文书
2015年音乐教研组工作总结
2015/07/22 职场文书
2016大学生入党积极分子心得体会
2016/01/06 职场文书
《我是什么》教学反思
2016/02/16 职场文书
中学教代会开幕词
2016/03/04 职场文书
创业计划书之餐饮
2019/09/02 职场文书
用Python将GIF动图分解成多张静态图片
2021/06/11 Python
解决MultipartFile.transferTo(dest) 报FileNotFoundExcep的问题
2021/07/01 Java/Android
SpringCloud Function SpEL注入漏洞分析及环境搭建
2022/04/08 Java/Android