欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 美景 > setInterval问题以及前端如何实现精确的倒计时

setInterval问题以及前端如何实现精确的倒计时

2025/4/10 8:22:01 来源:https://blog.csdn.net/m0_71288644/article/details/147025150  浏览:    关键词:setInterval问题以及前端如何实现精确的倒计时

一、为什么setInterval不能实现

原因有两:1、js是单线程,基于事件循环执行其他任务(这里建议读者可以多去了解一下浏览器线程与事件循环相关知识)

                  2、setinterval是每隔delay时间,把逻辑放到任务队列中,而不是执行栈中,且如果setinterval中的回调函数执行较长时间,如有for循环等逻辑,那么随着每一次执行误差会越来越大,(会因执行延迟导致误差累积)

二、如何解决

1、webworker:适合长时间定时

原理:Worker独立于主线程运行,不受DOM渲染/事件处理等任务阻塞

思路:主线程向worker线程发送倒计时开始时间戳和总时长(ms)

           worker线程预先计算结束时间戳,通过结束时间戳 - 当前时间戳计算剩余时间,避免传统递减法的累积误差,通过postMessage向主线程发送(基于绝对时间计算剩余时间,而不是简单递减)

            主线程监听并显示UI

self.onmessage = function(e) {// 1. 接收主线程传递的初始参数const { startTime, duration } = e.data;  // 开始时间戳和总时长(ms)const endTime = startTime + duration;    // 预先计算结束时间戳function update() {// 2. 计算精确剩余时间const remaining = Math.max(0, endTime - Date.now());
// 这里也可以用performance.now() ws级别// 3. 向主线程发送实时数据self.postMessage({remaining: remaining,               // 精确到毫秒的剩余时间seconds: Math.ceil(remaining / 1000) // 向上取整的秒数(UI显示用)});if (remaining > 0) {// 4. 动态计算下次触发时间(误差补偿核心)const nextTick = remaining % 1000 || 1000;setTimeout(update, nextTick);}};update(); // 首次启动
};

有个缺点:就是主线程接收到应该渲染的事件后,也是需要去等待当前执行栈清空(比如正在运行的JS代码)和到达浏览器渲染周期才去渲染,实际延迟通常小于1帧(<16ms)这个方法还是有些不足,但是比传统的setinterval会好很多

2、requestAnimation:适合短时间定时

思路:与浏览器刷新率同步+performance.now() 微秒级别+requestAnimation去控制UI更新

这里有个注意点requestAnimation是控制UI渲染的,也就是会让倒计时ui16.6ms就会更新一次,避免了上一个方法中因为事件循环导致ui渲染的去查,精确计算剩余时间靠 performance.now()实现

function update() {const remaining = endTime - performance.now(); // 计算剩余时间if (remaining <= 0) {show("时间到!");return;}// 更新UI(但不需要每秒更新60次!)show(Math.ceil(remaining / 1000) + "秒"); requestAnimationFrame(update); // 继续循环
}requestAnimationFrame(update); // 启动

3、最好的是requestanimation与webworker+performance.now()结合 requestanimation解决ui渲染问题,webworker+performance.now()解决精确计时问题

4、服务器同步时间:适合抢购、秒杀等场景

  1. 同步阶段

    • 获取服务器时间与本地时间的差值 timeDiff

  2. 倒计时阶段

    • 始终通过 Date.now() + timeDiff 获取真实服务器时间

    • 基于服务器时间计算剩余时长

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词