setInterval倒计时切换页面后不准
背景
最近在做一个倒计时时,发现当切换浏览器tab后,再切回倒计时页面,倒计时的数据不准,比真正的剩余时间多,短时间还好,时间长了,计时器的误差会很大。
原因
倒计时是用setInterval每1000毫秒触发一次。
在进入页面时,计算剩余时间,把剩余时间用setInterval每1000毫秒触发一次进行减法。
但是由于浏览器的优化机制,为了更极致的优化,在切换tab之后浏览器会把setInterval的执行效率降低,在浏览器窗口非激活的状态下会停止工作或者以极慢的速度工作。那么这时候就不是1000毫秒减一次了,所以会有误差。
用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。
用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);}
}

也是一样的会出现误差
setInterval、setTimeout误差的不同之处
setInterval指定的是“开始执行”之间的间隔,并不考虑每次任务执行本身所消耗的时间。因此实际上,两次执行之间的间隔会小于指定的时间。比如,setInterval指定每 100ms 执行一次,每次执行需要 5ms,那么第一次执行结束后95毫秒,第二次执行就会开始。如果某次执行耗时特别长,比如需要105毫秒,那么它结束后,下一次执行就会立即开始。
为了确保两次执行之间有固定的间隔,可以不用setInterval,而是每次执行结束后,使用setTimeout指定下一次执行的具体时间。
模拟阻塞事件
setInterval
//阻塞代码
setInterval(function () {var n = 0while (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)

setTimeout
//阻塞代码
setInterval(function () {var n = 0while (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);}
}

可以看到加了一些阻塞线程的代码后,误差越来越严重,
在实际项目中,执行计时器的同时,会有很多其他异步阻塞事件,会导致倒计时功能不精确。
解决方案
1、setInterval每次触发的时候,重新计算剩余时间(误差在一分钟以内)
2、Web Workers(这个在nuxt中引入会报错,涉及到webpack改动较大,暂时不用)
3、进行误差修正,也就是获取到误差的值,并且根据这个误差值来动态调整我们执行回调的间隔时间
- 计算误差值
- 动态调整执行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倒计时切换页面后不准
背景 最近在做一个倒计时时,发现当切换浏览器tab后,再切回倒计时页面,倒计时的数据不准,比真正的剩余时间多,短时间还好,时间长了,计时器的误差会很大。 原因 倒计时是用setInterval每1000毫…...
信息安全三级概述
信息安全三级概述...
深入JVM:探索Java虚拟机
文章目录 1. JVM简介1.1 定义与核心作用1.2 JVM的跨平台特性 2. JVM内部结构深度探索2.1 类加载机制2.1.1 双亲委派模型2.1.2 OSGI框架2.1.3 类加载器分类 2.2 JVM运行时数据区2.2.1 程序计数器2.2.2 本地方法栈2.2.3 Java虚拟机栈 2.2.4 堆2.2.5 元数据区 2.3 JVM内存区域的性…...
【计算机网络】 RTT和RTO
文章目录 RTT——往返时延RTO(Retransmission Timeout)——超时重传时间 RTT——往返时延 RTT(Round-Trip Time)是计算机网络中的一个重要的性能指标,表示从发送端发送数据开始,到发送端接收到来自接收端的…...
Zabbix监控组件及流程
Zabbix 由5大组件构成 Zabbix Web、Zabbix Server、Zabbix Proxy、Zabbix Database、Zabbix Agent Zabbix监控系统具体监控系统流程如图: Zabbix Web Zabbix Web是基于PHP语言编写的WEB UI界面,展示Zabbix整个监控平台监控数据、配置信息、方便对整个…...
Type-C协议Ver2.0(学习笔记)
题记 本文以TYPE-C协议Ver2.0版本为基础,以直译为主,同时备注作者学习中遇到的问题与理解,如发现文中描述和协议原文有误,欢迎批评指正,感谢! 1 简介 随着USB接口的持续成功,需要调整USB技术…...
智慧工地:实现作业区域安全管控
智慧工地是围绕工程现场人、机、料、法、环及施工过程中质量、安全、进度、成本等各项数据满足工地多角色、多视角的有效监管,实现工程建设管理的降本增效。 建设工程安全文明施工与质量提升,全方位的监测施工人员、各类器械设备、消防安全隐患,并提前对风险进行预警…...
【Unity插件】实现多人在线游戏——Mirror插件的使用介绍
文章目录 前言导入Mirror插件 简单介绍一、RPC调用二、错误注意 基本使用一、创建场景的网络管理器二、创建一个玩家三、添加玩家初始生成位置四、玩家控制五、同步摄像机六、同步不同角色的名字和颜色修改七、同步动画八、同步子弹方法一方法二 九、聊天功能十、场景同步切换十…...
GeoSOS-FLUS未来土地利用变化情景模拟模型
软件简介 适用场景 GeoSOS-FLUS软件能较好的应用于土地利用变化模拟与未来土地利用情景 的预测和分析中,是进行地理空间模拟、参与空间优化、辅助决策制定的有效工 具。FLUS 模型可直接用于: 城市发展模拟及城市增长边界划定;城市内 部高分…...
IntelliJ IDEA使用_Debug操作
文章目录 版本说明图标和快捷键查看变量计算表达式条件断点多线程调试 版本说明 当前的IntelliJ IDEA 的版本是2021.2.2(下载IntelliJ IDEA) ps:不同版本一些图标和设置位置可能会存在差异,但应该大部分都差不多。 图标和快捷键…...
市场的新宠:4G智能手表
现在人们提到智能手表,健康监测、运动记录、接打电话等定是他不可或缺的功能,而其中通讯功能在绝大数多的智能手表上都是通过蓝牙实现的,需要让手表通过蓝牙连接到手机端来进行。在没有手机的情况下,配置再高的蓝牙智能手表也是“…...
Pytorch Advanced(一) Generative Adversarial Networks
生成对抗神经网络GAN,发挥神经网络的想象力,可以说是十分厉害了 参考 1、AI作家 2、将模糊图变清晰(去雨,去雾,去抖动,去马赛克等),这需要AI具有“想象力”,能脑补情节; 3、进行数…...
Python实操如何去除EXCEL表格中的公式并保留原有的数值
import xlwings as xw app xw.App(visibleTrue, add_bookFalse) # 创建一个不可见的Excel应用程序实例 wb app.books.open(rE:\公式.xlsx) # 打开Excel文件 sheet wb.sheets[DC] # 修改为你的工作表名称 # 假设需要清除公式的范围是A1到B10range_to_clear sheet.range(A…...
MFC串口通信控件MSCOMM32.OCX的安装注册
MSCOMM32.OCX是一个与Microsoft Corporation开发的MSComm控件相关联的文件。MSComm控件是软件应用程序用来与调制解调器、条形码读取器和其他串行设备等设备建立串行通信的通信控件。 下载地址1 https://download.csdn.net/download/m0_60352504/88345092 下载地址2 https://ww…...
27.顺序表练习题目(1)(2023王道数据结构2.2.3前8题)
【这里所有解答都写的是全部代码,目的是让大家能够直接复制上手运行,感受代码的运行过程,而不单单只是写了一个函数】 试题1:(王道2023数据结构综合应用题1) 从顺序表中删除具有最小值的元素(…...
Unity VideoPlayer 指定位置开始播放
如果 source是 videoclip(以下两种方式都可以): _videoPlayer.Play();Debug.Log("time: " _videoPlayer.clip.length);_videoPlayer.time 10; [SerializeField] VideoPlayer videoPlayer;public void SetClipWithTime(VideoClip…...
美团多场景建模的探索与实践
本文介绍了美团到家/站外投放团队在多场景建模技术方向上的探索与实践。基于外部投放的业务背景,本文提出了一种自适应的场景知识迁移和场景聚合技术,解决了在投放中面临外部海量流量带来的场景数量丰富、场景间差异大的问题,取得了明显的效果…...
第11篇:ESP32vscode_platformio_idf框架helloworld点亮LED
第1篇:Arduino与ESP32开发板的安装方法 第2篇:ESP32 helloword第一个程序示范点亮板载LED 第3篇:vscode搭建esp32 arduino开发环境 第4篇:vscodeplatformio搭建esp32 arduino开发环境 第5篇:doit_esp32_devkit_v1使用pmw呼吸灯实验 第6篇:ESP32连接无源喇叭播…...
React中的页面跳转方式详解
在React中,页面跳转通常通过路由来实现。React有多种路由库可供选择,其中最常用的是React Router。React Router提供了几种不同的跳转方式,包括使用组件进行页面跳转、使用组件进行重定向,以及使用编程式导航进行跳转。 使用组件进…...
Golang代码漏洞扫描工具介绍——govulncheck
Golang Golang作为一款近年来最火热的服务端语言之一,深受广大程序员的喜爱,笔者最近也在用,特别是高并发的场景下,golang易用性的优势十分明显,但笔者这次想要介绍的并不是golang本身,而且golang代码的漏洞…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
Git常用命令完全指南:从入门到精通
Git常用命令完全指南:从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...
在树莓派上添加音频输入设备的几种方法
在树莓派上添加音频输入设备可以通过以下步骤完成,具体方法取决于设备类型(如USB麦克风、3.5mm接口麦克风或HDMI音频输入)。以下是详细指南: 1. 连接音频输入设备 USB麦克风/声卡:直接插入树莓派的USB接口。3.5mm麦克…...
前端高频面试题2:浏览器/计算机网络
本专栏相关链接 前端高频面试题1:HTML/CSS 前端高频面试题2:浏览器/计算机网络 前端高频面试题3:JavaScript 1.什么是强缓存、协商缓存? 强缓存: 当浏览器请求资源时,首先检查本地缓存是否命中。如果命…...
