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 相关文章推荐
通过MSXML2自动获取QQ个人头像及在线情况(给初学者)
Jan 22 Javascript
textarea 控制输入字符字节数(示例代码)
Dec 27 Javascript
jQuery照片伸缩效果不影响其他元素的布局
May 09 Javascript
让浏览器DOM元素最后加载的js方法
Jul 29 Javascript
JS+CSS实现分类动态选择及移动功能效果代码
Oct 19 Javascript
js实现的奥运倒计时时钟效果代码
Dec 09 Javascript
jQuery的each循环用法简单示例
Jun 12 Javascript
jQuery ajax实现省市县三级联动
Mar 07 Javascript
JS实现瀑布流布局
Oct 21 Javascript
Angular7.2.7路由使用初体验
Mar 01 Javascript
Vue2.0+Vux搭建一个完整的移动webApp项目的示例
Mar 19 Javascript
JavaScript如何实现防止重复的网络请求的示例
Jan 28 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
法国:浪漫之都的咖啡文化
2021/03/03 咖啡文化
简单PHP上传图片、删除图片实现代码
2010/05/12 PHP
PHP导出Excel实例讲解
2016/01/24 PHP
使用git迁移Laravel项目至新开发环境的步骤详解
2020/04/06 PHP
javascript重写alert方法的实例代码
2013/03/29 Javascript
js substring从右边获取指定长度字符串(示例代码)
2013/12/23 Javascript
浅谈javascript回调函数
2014/12/07 Javascript
3个可以改善用户体验的AngularJS指令介绍
2015/06/18 Javascript
js弹出对话框方式小结
2015/11/17 Javascript
基于jQuery1.9版本如何判断浏览器版本类型
2016/01/12 Javascript
JavaScript中循环遍历Array与Map的方法小结
2016/03/12 Javascript
JavaScript几种数组去掉重复值的方法推荐
2016/04/12 Javascript
iframe中使用jquery进行查找的方法【案例分析】
2016/06/17 Javascript
js简单实现图片延迟加载的方法
2016/07/19 Javascript
从零开始学习Node.js系列教程二:文本提交与显示方法
2017/04/13 Javascript
JS设置手机验证码60s等待实现代码
2017/06/14 Javascript
vue 文件目录结构详解
2017/11/24 Javascript
React-native桥接Android原生开发详解
2018/01/17 Javascript
vue单页开发父子组件传值思路详解
2018/05/18 Javascript
Vue CLI3 如何支持less的方法示例
2018/08/29 Javascript
d3绘制基本的柱形图的实现代码
2018/12/12 Javascript
Vue中登录验证成功后保存token,并每次请求携带并验证token操作
2020/09/08 Javascript
在Django中管理Users和Permissions以及Groups的方法
2015/07/23 Python
使用python进行波形及频谱绘制的方法
2019/06/17 Python
在ipython notebook中使用argparse方式
2020/04/20 Python
CSS3 animation实现简易幻灯片轮播特效
2016/09/27 HTML / CSS
网页中的电话号码如何实现一键直呼效果_附示例
2016/03/15 HTML / CSS
Agoda香港:全球特价酒店预订
2017/05/07 全球购物
比驿:全球酒店比价网
2018/06/20 全球购物
大学生就业自我鉴定
2013/10/26 职场文书
《梅花魂》教学反思
2014/04/30 职场文书
服务标兵事迹材料
2014/05/04 职场文书
会计求职自荐信范文
2015/03/04 职场文书
幼儿园教研工作总结2015
2015/05/12 职场文书
教你解决往mysql数据库中存入汉字报错的方法
2021/05/06 MySQL
swagger如何返回map字段注释
2021/07/03 Java/Android