解决setInterval和setTimeout越来越慢的问题 您所在的位置:网站首页 华为nova5i为什么越来越卡 解决setInterval和setTimeout越来越慢的问题

解决setInterval和setTimeout越来越慢的问题

2024-03-24 08:24| 来源: 网络整理| 查看: 265

情景:后端返回一个时间差,前端将其格式化为xx时xx分xx秒后展示在页面上,然后每隔1s刷新一下倒计时。写的时候发现有不少问题,遂研究记录一下。

一、将时间差转化为xx时xx分xx秒 export const getFormatTime = (durTime: number) => { let remain = durTime; const hour = Math.floor(remain / (60 * 60 * 1000)); remain = remain % 3600000; const minute = Math.floor(remain / (60 * 1000)); remain = remain % 60000; const second = Math.floor(remain / 1000); return { hour, minute, second, }; };

这里很简单就不赘述了。

二、每隔1s刷新一下倒计时 方案1、使用 setInterval // 假设剩余时间为1小时1分10秒 let time = 3670000; setInterval(() => { time = time - 1000; const data = getFormatTime(time); // 在这更新页面数据 }, 1000)

但我印象中setInterval是有问题的,就去了解了一下,有如下几个问题:

1、setInterval会无视回调函数里的错误,而不会中止。

let count = 1; setInterval(function () { count++; console.log(count); if (count % 3 === 0) throw new Error('setInterval报错'); }, 1000)

这会让一些bug难以被排查出来。

2、setInterval会在任何情况下定时执行,即使我们不希望如此。比如每隔3s轮询一次,但是用户网络很差可能隔了十几秒才拿到上一次请求的结果,这就会导致请求积压。

3、setInterval内部代码的执行时间大于延迟时间时,当次回调会被跳过。

let startTime = new Date().getTime(); setInterval(() => { while (new Date().getTime() setTimeout(() => { time = time - 1000; const data = getFormatTime(time); console.log(data); // 拿到data更新页面数据 fn() // 新开定时器 }, 1000) } fn()

但由于setTimeout是最小延迟时间,这样写会导致误差延迟越来越大,倒计时越来越不准。这就需要每次设置的延迟时间动态调整,以达到消除误差的目的,代码如下:

let time = 3670000; const startTime = new Date().getTime(); let count = 0; const fn = (nextTime) => { setTimeout(() => { time = time - 1000; const data = getFormatTime(time); console.log(data); // 拿到data更新页面数据 count++ const offset = new Date().getTime() - (startTime + count * 1000); // 误差时间 fn(1000 - offset) }, nextTime) } fn(1000)

看起来没有什么问题,但实际上不论是setInterval还是setTimeout都存在一个问题,当页面被切换到后台的时候,由于浏览器的优化策略,定时器的执行会被延迟,在大约5分钟后延迟到1分钟左右执行一次。

以下方案均是在这两个方案的基础上,解决了存在的问题。

方案3、监听页面切换 let totalTime = 3670000; // 总时间 let leftTime = totalTime // 剩余时间 let startTime = new Date().getTime(); // 计时器的开始时间 let count = 0; // 计时器的执行次数 let timer = 0; // 定时器id const fn = (nextTime) => { timer = setTimeout(() => { leftTime = leftTime - 1000; const data = getFormatTime(leftTime); console.log(data); // 拿到data更新页面数据 count++ const offset = new Date().getTime() - (startTime + count * 1000); // 误差时间 fn(1000 - offset) }, nextTime) } fn(1000) document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'hidden') { clearTimeout(timer) } else { totalTime = totalTime - (new Date().getTime() - startTime) if (totalTime if (time - pass * 1000 console.log('主线程接收到了:' + event.data); };

worker线程:

const workercode = () => { const getFormatTime = (durTime: number) => { let remain = durTime; const hour = Math.floor(remain / (60 * 60 * 1000)); remain = remain % 3600000; const minute = Math.floor(remain / (60 * 1000)); remain = remain % 60000; const second = Math.floor(remain / 1000); return { hour, minute, second, }; }; let time = 3670000; setInterval(() => { time = time - 1000; if (time type: 'application/javascript' }); const worker_script = URL.createObjectURL(blob); export default worker_script;

这种方案代码较多,但也没有啥学习成本,很容易理解。感兴趣的同学可以看一下这篇文章:web worker 使用教程

三、总结

上面给出的5种方案其实在特定的场景下都是可以使用的,具体问题具体分析。就我个人而言,还是更喜欢方案3和方案5,这两种方案在无需引入额外依赖的情况下,较为完美的解决了定时器的各种问题。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有