settimeout时间误差_采集终端和电能表日计时误差

settimeout时间误差_采集终端和电能表日计时误差setInterval指定的是“开始执行”之间的间隔,并不考虑每次任务执行本身所消耗的时间。因此实际上,两次执行之间的间隔会小于指定的时间。比如,setInterval指定每100ms执行一次,每次执行需要5ms,那么第一次执行结束后95毫秒,第二次执行就会开始。如果某次执行耗时特别长,比如需要105毫秒,那么它结束后,下一次执行就会立即开始。为了确保两次执行之间有固定的间隔,可以不用setInterval,而是每次执行结束后,使用setTimeout指定下一次执行的具体时间。

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

一、背景

最近项目中加了一个计时器,我是用setInterval来实现计时的,用于显示订单剩余支付时间,但我发现,短时间还好,时间长了,计时器的误差会很大。

二、问题

我现在来模拟一下这个问题

1.用setInterval实现计时

来看段代码

var start = new Date().getTime(), count = 0;
var interval = setInterval(function () {
    count++
    console.log(new Date().getTime() - (start + count * 1000) + 'ms')
    if(count == 10){
    clearInterval(interval);
    }
}, 1000)

在这里插入图片描述

可以看到,我打印的new Date().getTime() – (start + count * 1000) ,
也就是每次计时的误差,理想情况下,应该是0。

2.用setTimeout实现计时

var start = new Date().getTime(), count = 0,interval = 1000;
var timer = setTimeout(doFunc,interval);
function doFunc(){
    count++
    console.log(new Date().getTime() - (start + count * 1000) + 'ms');
  if(count < 10){
	    timer = setTimeout(doFunc,interval);
    }
}

在这里插入图片描述
也是一样的会出现误差

三、分析

1.出现误差的原因

setInterval、setTimeout实现都会出现误差,这源于js的单线程。
他们的回调函数并不是到时后立即执行,而是等系统计算资源空闲下来后才会执行。
setInterval、setTimeout都属于宏任务。
有关事件循环机制的内容,可参考文章
JavaScript中的Event Loop(事件循环)机制(含图解)

2.setInterval、setTimeout误差的不同之处

setInterval指定的是“开始执行”之间的间隔,并不考虑每次任务执行本身所消耗的时间。因此实际上,两次执行之间的间隔会小于指定的时间。比如,setInterval指定每 100ms 执行一次,每次执行需要 5ms,那么第一次执行结束后95毫秒,第二次执行就会开始。如果某次执行耗时特别长,比如需要105毫秒,那么它结束后,下一次执行就会立即开始。

为了确保两次执行之间有固定的间隔,可以不用setInterval,而是每次执行结束后,使用setTimeout指定下一次执行的具体时间。

四、模拟阻塞事件

现在来模拟一下,加一些阻塞线程的代码试试

1.setInterval

如:

//阻塞代码
setInterval(function () {
  var n = 0
  while (n++ < 1000000000);
}, 1000)

var start = new Date().getTime(), count = 0;
var interval = setInterval(function () {
    count++
    console.log(new Date().getTime() - (start + count * 1000) + 'ms')
    if(count == 10){
    clearInterval(interval);
    }
}, 1000)

在这里插入图片描述

2.setTimeout

//阻塞代码
setInterval(function () {
  var n = 0
  while (n++ < 1000000000);
}, 1000)

var start = new Date().getTime(), count = 0,interval = 1000;
var timer = setTimeout(doFunc,interval);
function doFunc(){
    count++
    console.log(new Date().getTime() - (start + count * 1000) + 'ms');
  if(count < 10){
	    timer = setTimeout(doFunc,interval);
    }
}

在这里插入图片描述

可以看到加了一些阻塞线程的代码后,误差越来越严重,
在实际项目中,执行计时器的同时,会有很多其他异步阻塞事件,会导致倒计时功能不精确。

四、解决方案

我们需要进行误差修正,也就是获取到误差的值,并且根据这个误差值来动态调整我们执行回调的间隔时间

  • 计算误差值
  • 动态调整执行setTimeout的间隔

加上动态误差修正

var start = new Date().getTime(), count = 0,interval = 1000;
var offset = 0;//误差时间
var nextTime = interval - offset;//原本间隔时间 - 误差时间
var timer = setTimeout(doFunc,nextTime);
function doFunc(){
    count++
    console.log(new Date().getTime() - (start + count * interval) + 'ms');
     offset = new Date().getTime() - (start + count * interval);
    nextTime = interval - offset;
    if (nextTime < 0) { nextTime = 0; }
  if(count < 10){
	    timer = setTimeout(doFunc,nextTime);
    }
}

试试效果:

在这里插入图片描述

我把每次的nextTime打印出来看看:
在这里插入图片描述

可以看到每次的nextTime都会根据上次的误差值来动态调整,以尽量减少整体的误差。

拓展

最近发现一个新的问题,
切换页面导致计时器停止,setInterval切换页面后不执行

原因
因为浏览器的优化原因,setTimeout()和setInterval(),在浏览器窗口非激活的状态下会停止工作或者以极慢的速度工作。

解决方案
准备用 Web Workers 去做一个优化。

Web WorkersWeb Workers 是 HTML5
提供的一个javascript多线程解决方案,可以将一些大计算量的代码交由web Worker运行而不冻结用户界面。

参考
https://blog.csdn.net/lhz_333/article/details/105678627

本文链接https://blog.csdn.net/qq_39903567/article/details/115392972

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/188868.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 关于insertBefore是怎么使用的

    关于insertBefore是怎么使用的insertBefore接收两个参数第一个参数是将要进行插前操作的对象第二个参数是被插前的对象也可以称为参考对象调用者为你要操作的元素的父级如下例:<!DOCTYPE ht

  • thinkphp3.1课程 1-1 为什么thinkphp在开发好后需要关掉开发模式

    thinkphp3.1课程 1-1 为什么thinkphp在开发好后需要关掉开发模式

  • python+opencv图像模板匹配—多模板匹配

    python+opencv图像模板匹配—多模板匹配

  • databus教程_搭建区观察记录表

    databus教程_搭建区观察记录表最近公司因需要同步oracle数据到mysql,调研了Datax对于大数据量的同步代价有些大。开源的databus需要对源码做二次开发,才可以使用,前期我们搭建后,用自带的person表做了测试。确认可行后研发更改了源码。准备工作:1.配制gradle和java2.ojdbc6-11.2.0.2.0.jar放到如下目录:databus-master/sandbox-repo/com/oracle/ojdbc6/11.2.0.2.0/更改defaultEnvironment.gradl

  • 三极管开关电路设计过程[通俗易懂]

    三极管开关电路设计过程[通俗易懂]三极管作为开关,是三极管工作于饱和区,以NPN型三极管为例(以下全部是)如图所示:当Vin=0时,三极管b-e之间没有正向偏置,而截止,相当于断开状态,此时Vce=Vcc,c极电流Ic=0;当三极管闭合(处于饱和区),负载Rc与三极管相当于串联,流经Rc的电流,通过欧姆定律可知,Ic=(Vcc-Vce)/Rc,(此时Ic为为饱和电流,即c极所能达到最大的电流,Vce为c极与e极的饱和电压,…

  • pt100温度传感器参数(pt100温度传感器原理)

    WZP-P系列贴片式pt100温度传感器主要用于测量物体表面的温度,它通过螺钉或其它固定方式将传感器贴在物体表面,实现较理想的测温效果。贴片式温度传感器和被测物体接触面积大,接触紧密,所以在一些表面温度测量方面具有比较明显的优势:测温准确性高、反应速度快,体积小方便固定安装。型号技术参数WZP-P1.铂电阻:Pt100、Pt500、Pt1000测温范围:(-80~300)℃2.常用精度:A级:…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号