当前位置: 首页 > Web前端 > HTML

为什么写倒计时总是出错

时间:2023-03-28 15:45:48 HTML

在日常需求中,我们经常需要写倒计时功能。但是有时候会发现速度不一样,那到底是怎么回事呢?我们先想一想,写倒计时函数应该用setInterval还是setTimeout?假设我们使用setInterval,我们可能会这样写letinterval=1000letcountdown=()=>{//dosometing...}countdown()setInterval(countdown,interval)我们可能认为它的执行顺序是这样的现在我把它执行通常变得大于其间隔。我们再来看看。我们发现在执行完回调后,我们并没有等一秒钟就继续执行,而是在执行完回调后立即重新开始执行。这是因为setInterval会在达到间隔时间后执行。检查是否有正在执行的回调。如果是这样,等待下一个周期。不管回调执行800毫秒还是2000毫秒,只要间隔时间到了,就会尝试插入到事件队列中。所以我们要写倒计时,最好不要在回调里放太多逻辑,回调执行时间不能大于interval,否则两次执行之间就没有interval2.假设我们用setTimeout,我们可能会写letinterval=1000countdown(interval)constcountdown=(interval)=>{lettimer=setTimeout(()=>{clearTimeout(timer)//dosometing...countdown(interval)},interval)}使用setTimeout我们可以确保逻辑处理有一个准确的区间,不会出现上面的情况,但是我们会发现另一个问题。通过实验,我们会看到每次打印的间隔时间会越来越长。其实除了js的执行时间,还有一个地方会出错。我们来看看官方的描述。此外,mdn还推荐了如何使用DavidBaron的博客:setTimeoutwithashorterdelay我也放在这里!那么如何避免这个错误呢?我们可以通过计算来解决这个问题,附上完整代码/***倒计时工具*@param{object}option-配置项*@param{number}option.timeStemp-以毫秒为单位的时间戳*@param{number}[option.interval=1000]-间隔时间,默认1000毫秒*@param{Function}[option.callback]-回调*@returns{Function}cancelStopthetimer*注意(一定要注意):不管是用这个工具还是自己写,回调的整体执行时间不要超过interval*/constcountdownTool=function({timeStemp,interval:originalInterval=1000,callback=(resetTime)=>void0,}){if(!timeStemp||timeStemp<=0||timeStemp{停止=true}letcurIdx=1letinterval=originalIntervalletct=Date.now()countdown(interval)functioncountdown(interval){if(stop)返回lettimer=setTimeout(function(){clearTimeout(timer)letresetTime=timeStemp-originalInterval*curIdxif(resetTime<0)resetTime=0callback(resetTime)if(!resetTime)返回curIdx++letct2=Date.now()letdeviation=ct2-interval-ctif(deviation>=originalInterval||deviation<=0)deviation=5//防止恶意更改当地时间ct=Date.now()countdown(originalInterval-deviation-(ct-ct2))},interval)}returncancel}在控制台执行下,可以看到每次回调中获取的时间间隔在1000毫秒左右,时间不会增加。还有两点需要注意:1.由于js引擎对loadingloss的优化策略,页面显示和隐藏时会出现较多错误。我们可以在展示的时候重新执行timeStep。最好从服务器端获取参考。文章:window.setTimeout-WebAPI接口参考|MDNhttps://segmentfault.com/a/1190000040397253DavidBaron的博客:setTimeoutwithashorterdelay