【已解决】浏览器小化或者切换标签,倒计时不准确解决方案


在这里插入图片描述

问题出现原因

一般屏幕刷新率为60HZ,也就是1秒刷新60次,大概17毫秒刷新一次。确保每17毫秒都执行代码则不会出现任何问题,由于定时器会收到JS事件队列的宏任务、微任务的影响,所以并不可能保证每17毫秒都执行一次,可能会有延迟,出现丢帧、卡顿的现象。
并且当浏览器标签切换到后台时,浏览器为了提高性能、节省电池和系统资源,以及减少不必要的计算开销,会对特定的任务进行节流后者延迟执行。

    let leftTime = 600 * 1000;
    function cutdownTime() {
    	let interval = setInterval(() => {
    		const currentTime = new Date();
    		if (leftTime == 0) {
    			console.log('结束倒计时')
    			clearInterval(interval)
    		} else {
    			leftTime -= 1;
    			console.log('剩余时间:', leftTime,'当前时间秒数', currentTime.getSeconds())
    		}
    	}, 1000)
    }
    window.addEventListener("visibilitychange", () => {
    	if (document.hidden) {
    		console.log('页面隐藏')
    	}
    })
    cutdownTime()

解决方案

提供两种解决方案,requestAnimationFrame以及Web Workers

1、使用requestAnimationFrame

使用requestAnimationFramerequestAnimationFrame可以按照显示器的刷新率来调度动画帧,能够十分精准严格的卡住显示器刷新的时间,比如60HZ显示器会自动大概17ms执行一次,对于120HZ显示器大概9ms执行一次。 requestAnimationFrame 的 MDN地址

		//设置结束时间为当前时间的10s后结束
		const endTime = Date.now() + 10 * 1000;
		function updateCountdown() {
		    //当前时间
			const currentTime = Date.now();
			// 时间差
			const tiemDifference = endTime - currentTime;
			if (tiemDifference == 0) {
				console.log('倒计时结束')
			} else {
				//计算剩余的时间,时:分:秒
				const seconds = Math.floor((tiemDifference / 1000) % 60)
				const minutes = Math.floor((tiemDifference / 1000 / 60) % 60)
				const hours = Math.floor((tiemDifference / 1000 / 60 / 60) % 24)
				console.log(`剩余时间:${hours}:${minutes}:${seconds}`)
				requestAnimationFrame(updateCountdown)
			}
		}
		requestAnimationFrame(updateCountdown)

2、使用Web Workers

Web Workers可以开辟一个新的线程执行JS代码,不会受到主线程阻塞的影响,所以可以使用它来解决倒计时不准确的问题。

//index.html
	<script type="module">
		// import * as Worker from "./webworks.js"
		let endTime = Date.now() + 10 * 1000;
		// 在 Web Worker 中执行倒计时逻辑
		const worker = new Worker('./webworks.js');
		worker.postMessage(endTime);
		// 主线程监听 Web Worker 的消息
		worker.onmessage = (event) => {
			const remainingTime = event.data;
			console.log(remainingTime, 'remainingTime')
			//如果剩余时间结束则停止线程
			//Worker线程被终止,就无法重新启动或恢复其执行。
			//因此终止Worker线程 之后,如果需要重新执行相同的任务,需要重新创建一个新的 Worker 实例。
			if (remainingTime) worker.terminate();
		}
	</script>
//webworks.js  监听主线程传递的目标时间
self.onmessage = function(event) {
	const targetDate = event.data;
  
	// 开始执行倒计时逻辑
	setInterval(function() {
	  const currentTime = Date.now();
	  const timeDifference = targetDate - currentTime;

	  // 将剩余时间发送回主线程
	  self.postMessage(timeDifference > 0 ? timeDifference : 0);
	}, 1000); // 每隔一秒钟更新一次时间
  };

可能会出现下面的报错信息

3.html:1 Access to script at 'file:///Users/zbs/study/%E6%B5%8F%E8%A7%88%E5%99%A8%E4%BC%98%E5%8C%96%E7%AD%96%E7%95%A5%E5%AF%B9%E5%AE%9A%E6%97%B6%E5%99%A8%E7%9A%84%E5%BD%B1%E5%93%8D/webworks.js' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, isolated-app, chrome-extension, chrome, https, chrome-untrusted.

这个错误说明浏览器拦截了对本地文件系统(file://)的跨域请求。通常 Web Worker 是不能直接从本地文件系统中加载的,这是浏览器的安全策略所限制的

解决方案:

本地服务器启动代码,我用的是Five Server,这样就可以通过 http:// 或 https:// 协议访问你的网页,而不是通过 file:// 协议。
在这里插入图片描述

浏览器地址就变成了以http开头

在这里插入图片描述

好书推荐

TypeScript + Vue.js 前端开发从入门到精通
本书以一个一线前端架构师的视角,深入浅出地介绍TypeScript与Vue.js整合开发大型前端应用的全部技术细节。

全书共17个章节,主要内容包括TypeScript基础、面向对象编程、Vue中的模板、组件属性和方法、用户交互处理、组件基础与进阶、Vue响应性编程、动画技术、脚手架Vue CLI和Vite工具的使用、Element Plus UI组件库以及基于Vue的网络框架vue-axios的应用等。此外,本书还涵盖Vue路由管理和状态管理的内容,并通过实战编程技术论坛系统项目的开发,让读者巩固所学的知识,全面提升自己的前端开发技能。

在这里插入图片描述

  • 47
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 22
    评论
多任务定时器能够完成现有定时软件的大多数功能,其中包括:   任务启动方式:     手动启动      每天的某个时间段启动  (新)      每周某天的某个时间段启动(新)      每月某日的某个时间段启动(新)      每隔N天后启动     (新)      按日期段启动      (新)      系统运行N久后启动   (新)         动作执行方式:     立即执行      倒计时执行      循环执行      定时执行   动作种类:     关机      重启      注销      待机      关闭屏幕      打开文件      关闭进程      打开网址      文字提示      播放音乐      音量设置      等待      执行另一个任务 (新) 2: 而且还有:多任务运行、多动作执行、浮动窗口显示......   用户可以根据自己的需要设置各种任务,并可方便的随时执行。而任务可执行的动作更可 添加多个,如文字提示的同时播放音乐。动作的数量没有限制,使得软件能够实现用户各种想 要的效果。同时,从2.1版开始,增加了多任务执行的功能,可以根据需要启动多个任务。新增 的功能势必能让你使用起来更加方便。   此外,你是否发生过其他定时软件在执行时难以知道其执行状态的情况呢?多任务定时器贴心 的为你设置了一个浮动窗口,只需占用显示器一点点空间,便可以随时知道任务状态,同时, 你还可以通过对浮动窗口的参数进行设置,使浮动窗口更加个性化。   从2.1版开始,通过几个简单的步骤,更可让浮动窗口以不规则窗口的形式显示(步骤见【基础教程】)。 3: 界面美观,操作人性    多任务定时器在经过用户反馈后,进行了各种细微的改进。2.1版的界面更  经过了较大的调整,更加美观,易用。    其余的改进特点有:    方便快速使用的简洁模式。    功能更加强大的任务模式。     改进最常使用的【文字提示】动作,为其配备更加合理美观的提示窗口。    提供浮动窗口的更多可设参数,小到字体,大到窗口形状,都可以进行设置。 多任务执行功能实现起来其实不难,但是在一些方面上没能想到一个 较好的解决方案,例如:多任务执行会不会带来混乱、多任务执行时浮动窗口要如何 显示各个任务信息等。总不能把一个尚未处理好的功能添加进来吧?于是这个功能就 一直拖着没加。不过好在最终还是为这些问题想到了解决方案,并把这个功能添加了 进来。   下面是与多任务执行的一些相关介绍: 1、每个任务都有四种状态:未启动、检测中、执行中以及已自动启动   未启动:  任务需要用户手动启动。   检测中:  任务属于自动启动的,此时软件正在检测其启动条件。   执行中:  任务现在正在执行。   已自动启动:任务已被自动启动并执行完成。   2、当你希望所以任务都暂停自动启动时,取消选择该处即可。重新选择该   处后,多任务定时器便会重新检测并启动这些任务。 切换任务信息显示:   当有多个任务在执行时(3),浮动窗口会优先显示最早执行的任务的信息。 若你要显示其他正在执行的任务的信息,可以在【浮动窗口】里点击右键,在 【任务显示】里选择要显示的任务(4),在任务显示的子菜单中,任务以 【任务序号:任务名称】的形式显示。根据序号或任务名,便可以在任务模式窗 口中找到对应的任务了。 单击浮动窗口亦可切换任务信息显示:   为了更加方便合理的显示任务信息,在2.1版编写的后期,浮动窗口又被赋予 了新的功能:直接单击便可以切换任务显示。 -------------------------------------------------------------------------------- 浮动窗口的时间与日期显示:   原来的浮动窗口,仅能在空闲时显示当时间。而在2.1版,浮动窗口将显示 三种类型的内容。只要通过其菜单,便可以设置了。 -------------------------------------------------------------------------------- 任务启动方式说明:   手动启动:任务不自动启动,而是由用户进行启动   每天  :每天的某个时间段自动启动。   每周  :每周周一至周日的指定一天中的某个时间段自动启动。   每月  :每月某天的某个时段自动启动。   每隔  :每隔指定天数后启动。   按日期段:指定一个日期段,若当日期位于日期段中,则启动任务。   系统运行:当系统累计运行(累计时间从系统开机时计)指定时间后执行。 注意:   当一个任务被自动启动并执行完后,便要等到程序重新启动才会被继续检测 和启动。 -------------------------------------------------------------------------------- 任务执行方式说明:   倒计时执行:任务启动后,会倒计时指定时间后才开始执行其动作。   定时执行 :任务启动后,在指定时间执行动作。   循环执行 :任务启动后,会等待指定时间后执行其动作,并一直循环直到任务被停止。   立即执行 :任务一启动就马上执行其动作。 -------------------------------------------------------------------------------- 动作说明:   重启  :略   关机  : 略   待机  :进入休眠模式。   注销  :注销当用户后,转换到切换用户的界面。   关闭屏幕:略   等待  :等待指定秒数,最长为99999秒。(快捷模式无法使用)   设置音量:将当系统音量调整为指定的百分比,百分比越高,音量越高。   打开文件:打开任何文件,包括可执行文件(exe)。如果打开的文件未被关联,        则不能被打开。   打开网址:调用系统的默认浏览器,打开指定网址。   文字提醒:弹出对话框,对话框显示用户设置的文字。在程序设置中,有两种形式        的提示窗口可供选择。   播放音乐:播放wav格式的音乐。(若需要播放mp3或其他格式的文件,请使用        【打开文件】动作来完成)   关闭进程:关闭指定进程。点击【选择进程】按钮后,会有弹出进程窗口供你选择要        关闭的进程。若要关闭的程序未运行,则在进程表里面看不到。需要运行        该程序后,重新打开进程窗口就可以看到了。   执行任务:执行另一个任务。(快捷模式无法使用)        该动作有几点需要注意:        1、被执行的任务会被重新开始执行,无论其正在执行或否。        2、若要执行的任务已被删除,则执行该任务的动作会被标记为无效并不被执行。        3、可以执行动作所处的任务,效果同1。 -------------------------------------------------------------------------------- 调整动作执行速度:    默认情况下,动作的执行速度是每秒一个周期,即每秒执行一个任务。如果你 觉得慢,可以打开程序安装目录下的Setting.inf文件,找到ExecuteTime= 一栏。调整其 后的数字(毫秒为单位,1000毫秒=1秒),就可以修改动作的执行速度。该参数 的有效范围为 1~1000 毫秒。 需要注意的是:若改快执行速度,则等待动作的时间 也会由于变快而缩短哦,而且也会消耗更多系统资源,因此建议保留默认值。
实现倒计时可以使用setInterval()函数来定时执行代码。在小程序中,我们可以将倒计时的时间保存在Page对象的data中,然后在onLoad()函数中启动定时器,每隔一秒钟更新data中的倒计时时间。在切换时,可以使用wx.navigateTo()和wx.redirectTo()函数来进行面跳转,这些函数不会影响定时器的执行。下面是一个实现倒计时切换面的示例代码: ``` // pages/index/index.js Page({ data: { countdown: 60, // 倒计时时间 }, onLoad: function () { // 启动定时器 this.timer = setInterval(() => { if (this.data.countdown > 0) { this.setData({ countdown: this.data.countdown - 1, }); } else { clearInterval(this.timer); wx.navigateTo({ url: '/pages/result/result', }); } }, 1000); }, onUnload: function () { // 面卸载时清除定时器 clearInterval(this.timer); }, navigateToResult: function () { // 手动跳转到结果面 clearInterval(this.timer); wx.navigateTo({ url: '/pages/result/result', }); }, redirectToResult: function () { // 手动跳转到结果面 clearInterval(this.timer); wx.redirectTo({ url: '/pages/result/result', }); }, }); // pages/result/result.js Page({ // 结果面代码 }); ``` 在上面的代码中,onLoad()函数启动了一个定时器,每隔一秒钟更新data中的countdown值,当countdown值为0时,清除定时器并跳转到结果面。在面卸载时,需要清除定时器以避免内存泄漏。可以使用wx.navigateTo()和wx.redirectTo()函数手动跳转到结果面,这些函数不会影响定时器的执行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不叫猫先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值