首页 > 其他分享 >js -- setTimeout 实现倒计时不准确的问题

js -- setTimeout 实现倒计时不准确的问题

时间:2022-08-30 16:33:08浏览次数:101  
标签:const -- timer js countdown Date setTimeout 1000

setTimeout、setInterval 属于定时触发器线程属于 macrotask,它的回调会受到GUI渲染、事件触发、http请求、等的影响。所以这两个不适合做精准的定时。最好的方法是定时矫正,用 new Date(targetDate:Date - new Date ) 格式化成你需要的时分秒即可。

  1. setTimeout、setInterval 等 timer 的执行时间点会受到js同步代码、microtask、ui rendering等的影响,导致设置的delay expired之后无法马上执行;

  2. timer有 节流(throttle) 机制,可以去mdn详细了解下。总之,不要依赖 timer 去做准确的计时计算。PS: 深入使用setTimeout等方法前建议先了解下event loop机制。

重点就是你的 setTimeout 回调函数执行的时机,比较说倒计时,每次我们的回调函数执行时,都要获取当前时间,与函数执行完毕之后的时间,它们两个时间的差就是你的函数执行时间,然后再用 1s 减去函数执行时间,就是下次 setTimeout 执行的时机;
不建议用setInterval,假如函数执行时间较长,则会跳过一次执行。建议用setTimeout递归的方式实现

start = (new Date()).getTime()
setTimeout(() => {
    b = undefined;
    for(var a = 0 ; a < 10000 ; a++) {
           b = a;
    }
    end = (new Date()).getTime()
    excuTime = end - start;
    console.log('excuTime: ', excuTime) // 输出:1003
}, 1000)

下次 setTimeout 的执行时机应该时 1000-excuTime ,通过这样不断修正,来达到尽量的精准性。

倒计时 计算时间差(服务器获取时间)

this.nowDate = Math.floor((new Date().getTime()) / 1000) * 1000 或 res.data.second * 1000 (服务器获取的10位时间戳)
handleCountTime() {
  clearTimeout(this.timer)
  const t1 = Date.now()
  let c1 = 0 // 递归次数
  const interval = 1000 // 间隔
  const sellStartTime = this.goodsDetail.sellStartTime // 售卖开始时间
  if (!sellStartTime) return null
  // let nowDate = this.systemTime
  // if(sellStartTime < nowDate) return false
  var timeDifference = parseInt(sellStartTime - this.nowDate) // 相差的总秒数

  const twentyFour = 24 * 60 * 60 * 1000
  if (timeDifference > twentyFour) return null

  this.countdown.h = Math.floor(timeDifference / 1000 / 60 / 60 % 24)
  this.countdown.m = Math.floor(timeDifference / 1000 / 60 % 60)
  this.countdown.s = Math.floor(timeDifference / 1000 % 60)
  this.countdown.h = this.countdown.h < 10 ? '0' + this.countdown.h : this.countdown.h
  this.countdown.m = this.countdown.m < 10 ? '0' + this.countdown.m : this.countdown.m
  this.countdown.s = this.countdown.s < 10 ? '0' + this.countdown.s : this.countdown.s

  if (timeDifference < 0) {
    this.showCountdown = false
    if (this.goodsDetail.sellStatus === 0) { // 改变页面状态
      this.goodsDetail.sellStatus = 1
    }
    clearTimeout(this.timer)
  } else if (timeDifference === 0) {
    this.showCountdown = true
    if (this.goodsDetail.sellStatus === 0) {
      this.goodsDetail.sellStatus = 1
    }
    this.nowDate += 1000
    // 计算误差
    const offset = Date.now() - (t1 + c1 * interval)
    const nextTime = interval - offset
    c1++
    this.timer = setTimeout(this.handleCountTime, nextTime)
  } else {
    this.showCountdown = true
    this.nowDate += 1000
    // 计算误差
    const offset = Date.now() - (t1 + c1 * interval)
    const nextTime = interval - offset
    c1++
    this.timer = setTimeout(this.handleCountTime, nextTime)
  }
}

获取本地 new Date() 的方法详见 https://www.cnblogs.com/lisaShare/p/11164541.html

标签:const,--,timer,js,countdown,Date,setTimeout,1000
From: https://www.cnblogs.com/lisaShare/p/12830783.html

相关文章

  • 【防忘笔记】一个例子理解Pytorch中一维卷积nn.Conv1d
    一维卷积层的各项参数如下torch.nn.Conv1d(in_channels,out_channels,kernel_size,stride=1,padding=0,dilation=1,groups=1,bias=True,padding_mode='zeros',de......
  • C20220711T4 移动
    牛牛从0出发走到\(n+1\),每秒可以选择向前走一步,向后走一步或者不走,有一些时刻不让呆在某一格,求最短到达时间,\(n\leq10^5\)。这是一道很神奇的压轴题(其实并没有什么......
  • gradle
    安装aptinstallgradlegradle-v编译gradleclean打包gradlebuild--------------手动安装gradlewgethttps://services.gradle.org/d......
  • P4551 最长异或路径
    给定树上\(n\)个点和边权,求两点间所有边权的异或和最大。\(n\leq10^5\)。首先如果假定一个根,那么所有点到根的距离\(dis[i]\)中两两异或得到的就是答案。(\(x,y\)......
  • OLW多级标题测试-1
    1安装Jenkins(1/3)1.1下载安装在官网上下载Windows版本的Jenkins:https://www.jenkins.io/download/选择最新的版本下载,安装到指定盘符,D:\Jenkins填写登录Windows的登录名和......
  • 第2节-安装jemeter
    第2节-安装jemeter     该文章参考文档为:JMeter官方文档(https://jmeter.apache.org/usermanual/get-started.html#requirements) 一、安装要求1、JDK   ......
  • gym-101667F Philosopher's Walk
    Philosopher'sWalk递归分治判断一下当前走的位置是属于\(4\)个块中的第几个块,然后递归计算一下在边长变小一倍后,他应该所处的位置,然后再对原位置进行旋转或平移的操作......
  • P4735 最大异或和
    给定一个非负整数序列\(\{a\}\),初始长度为\(n\)。有\(m\)个操作,有以下两种操作类型:Ax:添加操作,表示在序列末尾添加一个数\(x\),序列的长度\(n+1\)。Qlrx:询问操......
  • find-查抄文件
     在某目录下查找名为“elm.cc”的文件find/home/lijiajia/-nameelm.cc查找文件名中包含某字符(如"elm")的文件find/home/lijiajia/-name'*elm*'......
  • java-反射2
    1.javabean对象@MyAnnotation(value="hi")publicclassPersonextendsCreature<String>implementsComparable<String>,MyInterface{privateStringname;......