【问题标题】:Javascript setInterval doesn't work correctly when tab is not active选项卡未处于活动状态时,Javascript setInterval 无法正常工作
【发布时间】:2015-06-17 00:24:33
【问题描述】:
function initTimer(timeLeft) {
     var Me = this,
     TotalSeconds = 35,
     Seconds = Math.floor(timeLeft);

     var x = window.setInterval(function() {
         var timer = Seconds;

         if(timer === -1) { clearInterval(x); return; }

            $('#div').html('00:' + (timer < 10 ? '0' + timer : timer));
            Seconds--;

         },1000);
     }

我有这个代码。当此选项卡在浏览器中处于活动状态时,一切正常,但是当我更改选项卡并稍后在选项卡中返回时,它会出现问题。更准确地说,它不正确地显示时间。

我也试过 setTimeout,但问题是一样的。

我的一个想法是:HTML5 Web Workers...

但这里还有一个问题……浏览器支持。

有人可以帮忙解决这个问题吗? 如何编写 setInterval,即使选项卡未处于活动状态,它也能正常工作

【问题讨论】:

  • 你试过什么浏览器?
  • 浏览器可以并且在标签不活动的情况下可以进行油门调用 setInterval回调。您在设计代码时需要考虑到这一点。
  • 定时器不是实时的。如果您要求计时器每 1 秒触发一次,那么它向您保证的只是它不会早于 1 秒触发一次。以后可能会很多(尤其是在选项卡处于非活动状态时)。如果您想准确测量时间,请记录启动计时器的时间,然后在每次滴答时使用Date.now() 计算经过的时间
  • 进一步说明 - 即使标签 处于活动状态,setInterval 也只能保证 最少 时间,直到您的代码被调用。如果您要进行基于时间的计算,最好保持“开始时间”并以此为基础进行进一步的计算,而不是增加/减少变量。
  • @MattBurland 我看到你已经进一步说明了我的观点 :)

标签: javascript jquery setinterval


【解决方案1】:

使用Date 对象计算时间。不要依赖计时器在您请求时触发(它们不是实时的),因为您唯一的保证是它不会在您请求之前触发。它可能会触发很晚,尤其是对于非活动标签。试试这样的:

function  initTimer(periodInSeconds) {
            var end = Date.now() + periodInSeconds * 1000;


            var x = window.setInterval(function() {
                var timeLeft = Math.floor((end - Date.now()) / 1000);

                if(timeLeft < 0) { clearInterval(x); return; }

                $('#div').html('00:' + (timeLeft < 10 ? '0' + timeLeft : timeLeft));
            },200);
        }

initTimer(10);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="div"></div>

请注意,通过更频繁地检查它,我们可以确保它永远不会偏离太多。

【讨论】:

    【解决方案2】:

    JavaScript 计时器不可靠,即使标签处于活动状态。他们只保证至少您指定的时间已经过去;无法保证正是该时间,甚至任何接近它的时间,已经过去了。

    为了解决这个问题,每当间隔触发时,请注意它是什么时间。您实际上只需要跟踪两次:当前时间和上一个间隔触发的时间。通过从当前滴答的时间中减去上一个滴答的时间,您可以知道两者之间实际上经过了多少时间,并相应地运行您的计算。

    以下是类似这样的外观的基本轮廓:

    function  initTimer(timeLeft) {
            var Me           = this,
                TotalSeconds = 35,
                Seconds      = Math.floor(timeLeft),
                CurrentTime  = Date.now(),
                PreviousTime = null;
    
            var x = window.setInterval(function() {
                var timer = Seconds,
                    timePassed;
                PreviousTime = CurrentTime;
                CurrentTime = Date.now();
                timePassed = CurrentTime - PreviousTime;
    
                if(timer < 0) { clearInterval(x); return; }
    
                $('#div').html('00:' + (timer < 10 ? '0' + timer : timer));
                Seconds = Seconds - timePassed;
    
            },1000);
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-08-27
      • 2020-04-24
      • 2017-05-26
      • 2012-03-07
      • 2020-10-06
      • 2020-01-19
      • 2011-08-21
      相关资源
      最近更新 更多