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

 更新时间:2019年10月25日 22:23:35   作者:HyG  
关于写倒计时大家可能都都比较熟悉,使用 setTimeout 或 setInterval 就可以搞定。几秒钟或者几分钟的倒计时这样写没有问题,但是如果是长时间的倒计时,这样写就会不准确

关于写倒计时大家可能都都比较熟悉,使用 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 峰值达到非常高。

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

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

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

相关文章

  • Javascript 模式实例 中介者模式

    Javascript 模式实例 中介者模式

    页面上,用户会有很多的操作 ,每进行一次操作我们需要去展示操作的结果,在这里我们有了一个问题,我们应如何去展示不同的结果呢?
    2010-04-04
  • JavaScript中setInterval()和setTimeout()的用法及区别

    JavaScript中setInterval()和setTimeout()的用法及区别

    这篇文章主要给大家介绍了关于JavaScript中setInterval()和setTimeout()用法及区别的相关资料,Javascript的setTimeOut和setInterval函数应用非常广泛,它们都用来处理延时和定时任务,需要的朋友可以参考下
    2023-11-11
  • 详解如何使用JavaScript实现自定义的双向数据绑定

    详解如何使用JavaScript实现自定义的双向数据绑定

    双向数据绑定是一种编程模式,用于在用户界面和数据模型之间实现数据的同步更新,它允许用户界面中的数据变化自动更新到数据模型中,在这篇文章中,我会使用基于观察者模式和基于Proxy对象来实现JS的自定义双向数据绑定
    2023-08-08
  • bootstrap自定义样式之bootstrap实现侧边导航栏功能

    bootstrap自定义样式之bootstrap实现侧边导航栏功能

    bootstrap自带的响应式导航栏是向下滑动的,有时满足不了个性化的需求,需要做一个类似于android drawerLayout 侧滑的菜单,这就是我要实现的bootstrap自定义侧滑菜单。接下来通过本文给大家介绍bootstrap实现侧边导航栏功能,感兴趣的朋友一起看看吧
    2018-09-09
  • Js利用console计算代码运行时间的方法示例

    Js利用console计算代码运行时间的方法示例

    最近看了一本书,发现了个计算代码执行时间的方法,感觉还挺有用的,所以这篇文章主要给大家介绍了关于Javascript利用console计算代码运行时间的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下。
    2017-09-09
  • PHP PDO操作总结

    PHP PDO操作总结

    这篇文章主要介绍了PHP PDO操作总结,本文讲解了使用PDO连接数据库、执行基本查询、获取行数、遍历结果集、转义用户输入的特殊字符、exec()、预处理语句等内容,需要的朋友可以参考下
    2014-11-11
  • js 上传文件预览的简单实例

    js 上传文件预览的简单实例

    下面小编就为大家带来一篇js 上传文件预览的简单实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-08-08
  • safari,opera嵌入iframe页面cookie读取问题解决方法

    safari,opera嵌入iframe页面cookie读取问题解决方法

    最近做的合作网站嵌入到对方的iframe中去,在safari,opera和有些版本的搜狗浏览器(内核版本原因)中不能读到cookie。
    2010-06-06
  • JavaScript中事件冒泡机制示例详析

    JavaScript中事件冒泡机制示例详析

    这篇文章主要给大家介绍了关于JavaScript中事件冒泡机制的相关资料,文中详析介绍了什么是冒泡、冒泡捕获需要以及冒泡和捕获的具体区别,需要的的朋友可以参考下
    2021-06-06
  • 微信小程序动态显示项目倒计时效果

    微信小程序动态显示项目倒计时效果

    这篇文章主要为大家详细介绍了微信小程序动态显示项目倒计时,格式如4天7小时58分钟39秒,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06

最新评论