【已解决】浏览器小化或者切换标签,倒计时不准确解决方案
问题出现原因
一般屏幕刷新率为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
使用requestAnimationFrame
,requestAnimationFrame
可以按照显示器的刷新率来调度动画帧,能够十分精准严格的卡住显示器刷新的时间,比如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路由管理和状态管理的内容,并通过实战编程技术论坛系统项目的开发,让读者巩固所学的知识,全面提升自己的前端开发技能。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!