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 相关文章推荐
JavaScript的类型简单说明
Sep 03 Javascript
JS 添加网页桌面快捷方式的代码详细整理
Dec 27 Javascript
使用JavaScript制作一个简单的计数器的方法
Jul 07 Javascript
实例代码详解jquery.slides.js
Nov 16 Javascript
vuejs使用$emit和$on进行组件之间的传值的示例
Oct 04 Javascript
浅析Vue实例以及生命周期
Aug 14 Javascript
微信小程序动画(Animation)的实现及执行步骤
Oct 28 Javascript
jquery实现动态创建form并提交的方法示例
May 27 jQuery
javascript实现动态时钟的启动和停止
Jul 29 Javascript
vue.js自定义组件实现v-model双向数据绑定的示例代码
Jan 08 Javascript
Vue组件通信$attrs、$listeners实现原理解析
Sep 03 Javascript
javascript使用正则表达式实现注册登入校验
Sep 23 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
改进的IP计数器
2006/10/09 PHP
PHP获取当前完整URL地址的函数
2014/12/21 PHP
ubutu 16.04环境下,PHP与mysql数据库,网页登录验证实例讲解
2017/07/20 PHP
php接口实现拖拽排序功能
2018/04/23 PHP
技术男用来对妹子表白的百度首页
2014/07/23 Javascript
NodeJS学习笔记之网络编程
2014/08/03 NodeJs
Jquery实现兼容各大浏览器的Enter回车切换输入焦点的方法
2014/09/01 Javascript
使用纯javascript实现放大镜效果
2015/03/18 Javascript
JavaScript学习笔记之检测客户端类型是(引擎、浏览器、平台、操作系统、移动设备)
2015/12/03 Javascript
JS模拟简易滚动条效果代码(附demo源码)
2016/04/05 Javascript
easyui validatebox验证
2016/04/29 Javascript
原生JavaScript编写canvas版的连连看游戏
2016/05/29 Javascript
js 基础篇必看(点击事件轮播图的简单实现)
2016/08/20 Javascript
D3.js实现折线图的方法详解
2016/09/21 Javascript
学习 NodeJS 第八天:Socket 通讯实例
2016/12/21 NodeJs
微信小程序 122100版本更新问题解决方案
2016/12/22 Javascript
Bootstrap列表组学习使用
2017/02/09 Javascript
Angular.js实现多个checkbox只能选择一个的方法示例
2017/02/24 Javascript
VueJS如何引入css或者less文件的一些坑
2017/04/25 Javascript
详解VSCode配置启动Vue项目
2019/05/14 Javascript
python创建一个最简单http webserver服务器的方法
2015/05/08 Python
使用Mixin设计模式进行Python编程的方法讲解
2016/06/21 Python
python matlibplot绘制3D图形
2018/07/02 Python
Python面向对象之类的定义与继承用法示例
2019/01/14 Python
树莓派使用USB摄像头和motion实现监控
2019/06/22 Python
Python利用requests模块下载图片实例代码
2019/08/12 Python
python3实现微型的web服务器
2019/09/03 Python
PyQt5中多线程模块QThread使用方法的实现
2020/01/31 Python
HTML5+CSS3模仿优酷视频截图功能示例
2017/01/05 HTML / CSS
面向对象编程是如何提高软件开发水平的
2014/05/06 面试题
利达恒信公司.NET笔试题面试题
2016/03/05 面试题
编辑个人求职信范文
2013/09/21 职场文书
人力资源本科毕业生求职信
2014/06/04 职场文书
2014国庆节商场促销活动策划方案
2014/09/16 职场文书
法人单位授权委托书范文
2014/10/06 职场文书
Windows server 2003卸载和安装IIS的图文教程
2022/07/15 Servers