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 相关文章推荐
JQUERY获取form表单值的代码
Jul 17 Javascript
开发插件的两个方法jquery.fn.extend与jquery.extend
Nov 21 Javascript
js操作模态窗口及父子窗口间相互传值示例
Jun 09 Javascript
javascript创建动态表单的方法
Jul 25 Javascript
原生javascript+css3编写的3D魔方动画旋扭特效
Mar 14 Javascript
Markdown+Bootstrap图片自适应属性详解
May 21 Javascript
webpack+vue.js实现组件化详解
Oct 12 Javascript
js实现瀑布流效果(自动生成新的内容)
Mar 16 Javascript
详解Vue基于 Nuxt.js 实现服务端渲染(SSR)
Apr 05 Javascript
实例讲解Vue.js中router传参
Apr 22 Javascript
@angular前端项目代码优化之构建Api Tree的方法
Dec 24 Javascript
浅谈vue中使用编辑器vue-quill-editor踩过的坑
Aug 03 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 file_get_contents 函数超时的几种解决方法
2009/07/30 PHP
Zend Framework中的简单工厂模式 图文
2012/07/10 PHP
PHP+jQuery 注册模块的改进(一):验证码存入SESSION
2014/10/14 PHP
PHP输出日历表代码实例
2015/03/27 PHP
PHP7.0版本备注
2015/07/23 PHP
PHP中的数组处理函数实例总结
2016/01/09 PHP
PHP实现链式操作的三种方法详解
2017/11/16 PHP
juqery 学习之五 文档处理 包裹、替换、删除、复制
2011/02/11 Javascript
使用javascript实现ListBox左右全选,单选,多选,全请
2013/11/07 Javascript
jquery单行文字向上滚动效果的实现代码
2014/09/05 Javascript
原生javascript获取元素样式
2014/12/31 Javascript
JS实现不规则TAB选项卡效果代码
2015/09/16 Javascript
JS简单限制textarea内输入字符数量的方法
2015/10/14 Javascript
jQuery使用animate实现ul列表项相互飘动效果示例
2016/09/16 Javascript
JavaScript实现大图轮播效果
2017/01/11 Javascript
详解angular中的作用域及继承
2017/05/31 Javascript
vue v-model动态生成详解
2018/06/30 Javascript
值得收藏的八个常用的js正则表达式
2018/10/19 Javascript
微信小程序使用map组件实现获取定位城市天气或者指定城市天气数据功能
2019/01/22 Javascript
vue分页器组件编写方法详解
2019/06/28 Javascript
[06:21]完美世界亚洲区首席发行官竺琦TI3采访
2013/08/26 DOTA
Python判断直线和矩形是否相交的方法
2015/07/14 Python
Python生成密码库功能示例
2017/05/23 Python
利用ctypes获取numpy数组的指针方法
2019/02/12 Python
Python输出指定字符串的方法
2020/02/06 Python
深入解读CSS3中transform变换模型的渲染
2016/05/27 HTML / CSS
什么是网络协议
2016/04/07 面试题
大学毕业生通用自我评价
2014/01/05 职场文书
资源工程专业毕业生求职信
2014/02/27 职场文书
综合实践活动总结
2014/05/05 职场文书
基层党支部公开承诺书
2014/05/29 职场文书
关于教师节的演讲稿
2014/09/04 职场文书
《雷雨》教学反思
2016/02/20 职场文书
一些让Python代码简洁的实用技巧总结
2021/08/23 Python
ajax请求前端跨域问题原因及解决方案
2021/10/16 Javascript
Windows和Linux上部署Golang并运行程序
2022/04/22 Servers