一个倒计时功能引发的线上故障

阳光明媚的一天,和往常一样到公司,接水,然后优哉游哉的准备先上网看点东西(摸会儿鱼)。

当我正在知识的海洋遨游(摸鱼真快乐)的时候,突然有人拉我,说有用户反馈,倒计时没结束但是奖品显示都被抢完了。

用户还附上一个截图。

一看,的确,倒计时显示还有一分多钟,但是时间的确是已经超过活动开始时间了。

作为一个有着丰富摸鱼(划掉,coding)经验的前端,我第一反应就是倒计时写的不对。

扒开代码,发现这个地方之前的实现逻辑大致是这样的。

js 复制代码
const [restTime,setRestTime] = useState(100) 
useEffect(()=>{ 
    setTimeout(()=>{ 
        setRestTime(restTime-1) 
    },1000) },
    [restTime]
 )

看到代码的当时,我就崩溃了。2025年居然还有人写出如此令人发指的定时器代码吗?

难道是我穿越了?

前端水平倒退一万倍而我的不变(小说真好看啊)?

一脸懵,难顶。

但我还是奶昔的问了下,为什么会这么去写倒计时。

得到的答案是,网上都是这么写的。

除了无语,我还能说什么呢。


那么如何才能得到一个正确的倒计时功能呢。 我看网上也有不少例子,有的用多线程,有的说监听事件,等后台切回来的时候修正一下。 聒噪。 上面代码的基本原理是:

先设定一个初始值,每隔1s执行一次定时器,然后更新一下时间。

时间更新之后,state改变触发useEffect执行,之后又开始循环执行定时器。

看上去没什么问题,普通的测试也侧不出来啥。

但是只要稍微知道一些定时器原理的人都知道这样写是有问题的。

首先,定时器的执行周期是不准确的,你设定了1s执行1次,就一定是1s吗?只要学过时间循环的开发,都知道这肯定不是;

其次,由于浏览器的性能优化机制,在某些场景下定时器可能是会停止执行的,比较典型的就是浏览器或者app切到后台,页面不可见的时候。

那么倒计时功能应该怎么写才能避开上面的问题呢。

其实很简单,谜底就在谜面上。

既然是倒计时,那么一定有截止时间,用截止时间减去当前时间,不就是剩余时间吗?这不就是倒计时吗?

talk is cheap,我们直接看代码。

js 复制代码
// 定义倒计时 
const useCountDown = (endTime)=> {
    const [restTime,setRestTime] = useState(()=> endTime - Date.now())
    useEffect(()=>{ 
        setTimeout(()=>{ 
            setRestTime(endTime - Date.now()) },500) 
        },
     [restTime,endTime]]
     )
    return restTime 
 } 
// 使用 
// 如果后端下发的是截止时间戳
const restTime = useCountDown(new Date(endTime).getTime())
// 如果下发的是剩余时间
const restTime = useCountDown(endTime+Date.now()))

上面代码中,我们也依然是采用的在useEffect中去执行定时器的方式来更新时间。但是不同的是,我们每次都会拿结束时间减去当前时间来得到剩余时间。为了更新的更准确一些,我们将定时器的执行时间改为500ms一次。

这样不管你定时器是多久执行一次,我都能保证倒计时是准确的。

简单,好用。

下次不要再写错了哦。

相关推荐
雨季66615 分钟前
Flutter 三端应用实战:OpenHarmony 简易“动态内边距调节器”交互模式深度解析
javascript·flutter·ui·交互·dart
2601_9495936528 分钟前
基础入门 React Native 鸿蒙跨平台开发:卡片组件
react native·react.js·harmonyos
天人合一peng29 分钟前
Unity中button 和toggle监听事件函数有无参数
前端·unity·游戏引擎
会飞的战斗鸡1 小时前
JS中的链表(含leetcode例题)
javascript·leetcode·链表
方也_arkling1 小时前
别名路径联想提示。@/统一文件路径的配置
前端·javascript
毕设源码-朱学姐1 小时前
【开题答辩全过程】以 基于web教师继续教育系统的设计与实现为例,包含答辩的问题和答案
前端
qq_177767371 小时前
React Native鸿蒙跨平台剧集管理应用实现,包含主应用组件、剧集列表、分类筛选、搜索排序等功能模块
javascript·react native·react.js·交互·harmonyos
qq_177767372 小时前
React Native鸿蒙跨平台自定义复选框组件,通过样式数组实现选中/未选中状态的样式切换,使用链式调用替代样式数组,实现状态驱动的样式变化
javascript·react native·react.js·架构·ecmascript·harmonyos·媒体
web打印社区2 小时前
web-print-pdf:突破浏览器限制,实现专业级Web静默打印
前端·javascript·vue.js·electron·html
RFCEO2 小时前
前端编程 课程十三、:CSS核心基础1:CSS选择器
前端·css·css基础选择器详细教程·css类选择器使用方法·css类选择器命名规范·css后代选择器·精准选中嵌套元素