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 相关文章推荐
让mayfish支持mysqli数据库驱动的实现方法
May 22 Javascript
JQuery 选择和过滤方法代码总结
Nov 19 Javascript
Javascript数组的排序 sort()方法和reverse()方法
Jun 04 Javascript
两种方法实现文本框输入内容提示消失
Mar 17 Javascript
关于textarea提交的内容无法换行的解决办法
Apr 09 Javascript
JavaScript中使用Math.floor()方法对数字取整
Jun 15 Javascript
jQuery实现指定内容滚动同时左侧或其它地方不滚动的方法
Aug 08 Javascript
每天一篇javascript学习小结(RegExp对象)
Nov 17 Javascript
React-Native中props具体使用详解
Sep 04 Javascript
JS把字符串格式的时间转换成几秒前、几分钟前、几小时前、几天前等格式
Jul 10 Javascript
微信小程序 组件的外部样式externalClasses使用详解
Sep 06 Javascript
vue 实现用户登录方式的切换功能
Apr 14 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
第四节 构造函数和析构函数 [4]
2006/10/09 PHP
php cookie使用方法学习笔记分享
2013/11/07 PHP
让CodeIgniter数据库缓存自动过期的处理的方法
2014/06/12 PHP
ThinkPHP CURD方法之limit方法详解
2014/06/18 PHP
smarty内部日期函数html_select_date()用法实例分析
2015/07/08 PHP
php实现页面纯静态的实例代码
2017/06/21 PHP
PHP基于自定义函数实现的汉字转拼音功能实例
2017/09/30 PHP
详解PHP版本兼容之openssl调用参数
2018/07/25 PHP
JQuery Tips(4) 一些关于提高JQuery性能的Tips
2009/12/19 Javascript
javascript css styleFloat和cssFloat
2010/03/15 Javascript
Jquery右下角抖动、浮动 实例代码(兼容ie6、FF)
2013/08/15 Javascript
js 阻止子元素响应父元素的onmouseout事件具体实现
2013/12/23 Javascript
js获取当前页面的url网址信息
2014/06/12 Javascript
使用focus方法让光标默认停留在INPUT框
2014/07/29 Javascript
node.js中的fs.writeFile方法使用说明
2014/12/14 Javascript
Javascript基础教程之if条件语句
2015/01/18 Javascript
JavaScript使用push方法添加一个元素到数组末尾用法实例
2015/04/06 Javascript
JS实现放大、缩小及拖拽图片的方法【可兼容IE、火狐】
2016/08/23 Javascript
在JSP中如何实现MD5加密的方法
2016/11/02 Javascript
纯JavaScript实现实时反馈系统时间
2017/10/26 Javascript
jQuery点击页面其他部分隐藏下拉菜单功能
2018/11/27 jQuery
vuex state中的数组变化监听实例
2019/11/06 Javascript
Vue 路由间跳转和新开窗口的方式(query、params)
2019/12/25 Javascript
vue.js使用v-model实现父子组件间的双向通信示例
2020/02/05 Javascript
python3访问sina首页中文的处理方法
2014/02/24 Python
微信跳一跳python辅助软件思路及图像识别源码解析
2018/01/04 Python
django2+uwsgi+nginx上线部署到服务器Ubuntu16.04
2018/06/26 Python
python+jinja2实现接口数据批量生成工具
2019/08/28 Python
python中urllib.request和requests的使用及区别详解
2020/05/05 Python
python FTP编程基础入门
2021/02/27 Python
这段代码难道不该打印出56吗
2013/02/27 面试题
Linux文件操作命令都有哪些
2016/07/23 面试题
项目合作意向书范本
2014/04/01 职场文书
2015年班主任德育工作总结
2015/05/21 职场文书
西柏坡观后感
2015/06/08 职场文书
详解overflow:hidden的作用(溢出隐藏、清除浮动、解决外边距塌陷)
2021/07/01 HTML / CSS