【问题标题】:setTimeout speeds up with multiple tabssetTimeout 通过多个选项卡加速
【发布时间】:2011-05-24 15:10:17
【问题描述】:

我遇到了类似于this one 的 setTimeout 问题。但是该解决方案对我没有帮助,因为我无法在我的文件中使用 php。

我的网站有一个滑块,其中包含每 8 秒移动一次的图像列表。但是,当我在浏览器中打开几个选项卡然后再次切换回来时,它就发疯了。 滑块会立即一个接一个地移动图像,没有 8 秒的延时。

我只在 Chrome 和最新的 Firefox 中看到它。

**编辑:我检查了 console.log() 并且 setTimeout 在 clearTimeout 之前和之后返回相同的数字。不知道为什么。也许这也与它有关? **

编辑 2:我添加了一个小提琴:http://jsfiddle.net/Rembrand/qHGAq/8/

代码看起来像:

spotlight: {
    i: 0,
   timeOutSpotlight: null,

   init: function()
   {
       $('#spotlight .controls a').click(function(e) {

           // do stuff here to count and move images

           // Don't follow the link
           e.preventDefault();

           // Clear timeout
           clearTimeout(spotlight.timeOutSpotlight);

           // Some stuff here to calculate next item

           // Call next spotlight in 8 seconds
           spotlight.timeOutSpotlight = setTimeout(function () {
                spotlight.animate(spotlight.i);
            }, 8000);
       });

       // Select first item
       $('#spotlight .controls a.next:first').trigger('click');
   },

   animate: function(i)
   {
       $('#spotlight .controls li:eq(' + (spotlight.i) + ') a.next').trigger('click');
   }
}

【问题讨论】:

  • 只有在您打开同一个网站的新标签页,还是打开任何个新标签页并切换回来时才会出现这种情况?
  • 任何网站的随机标签。
  • 多么有趣。一些额外的测试可以帮助查看发生了什么 - 在回调期间,如果您 console.log 日期时间以查看代码命中的实际间隔 - 是 8 秒吗?而且,如果您离开页面 X # 秒,您是否看到在给定的经过时间内正确的控制台日志记录事件数?
  • 如果您继续为此苦苦挣扎,我建议您使用jsfiddle.net 复制它并在此处发布小提琴。
  • 小提琴添加:jsfiddle.net/Rembrand/qHGAq/3

标签: javascript jquery timer settimeout


【解决方案1】:

来自jQuery documentation

由于requestAnimationFrame() 的性质,你不应该 使用 setInterval 或 setTimeout 循环对动画进行排队。为了 保留 CPU 资源,支持 requestAnimationFrame 的浏览器 不显示窗口/选项卡时不会更新动画。如果 您继续通过 setInterval 或 setTimeout 对动画进行排队,同时 动画暂停,所有排队的动画将开始播放 当窗口/选项卡重新获得焦点时。为了避免这个潜在的问题, 在循环中使用上一个动画的回调,或附加一个 函数对元素 .queue() 设置超时以开始下一个 动画。

【讨论】:

    【解决方案2】:

    我终于找到了答案,这完全不是我所期望的。 罪魁祸首似乎是 jQuery 的 .animate(),我用它来移动滑块中的图像。

    我用这个来计算和移动我的图像位置:

    $('.spotlight-inner')
        .animate(
            { left: scrollToVal },
            {duration: 'slow'}
        )
     ;
    

    现在的问题似乎是,在某些浏览器中,当您切换到新选项卡并返回后,jQuery 的 .animate() 会保存动画并立即触发它们。所以我添加了一个过滤器来防止排队。该解决方案来自CSS-Tricks.com

    $('.spotlight-inner')
        .filter(':not(:animated)')
        .animate(
            { left: scrollToVal },
            {duration: 'slow'}
        )
    ;
    

    返回时看到的第一张幻灯片可能会有点跳动,但比以前的超高速旋转木马要好。

    摆弄完整代码here

    【讨论】:

    • 感谢您回来并发布您的答案。确实很有趣!
    • 你救了我几个小时的头发拔掉!!
    • 来说这对我有很大帮助,感谢您发布您的解决方案
    【解决方案3】:

    使用 jquery animate queue 属性有一种更简单的方法:

    $(this).animate({
        left: '+=100'
    }, {duration:500, queue:false});
    

    【讨论】:

    • 这确实是一段更短、更简单的代码。感谢分享!
    【解决方案4】:

    我不知道这是否会对您有所帮助,但它对我的幻灯片放映有所帮助。我所做的是每次我调用一个由于 setTimeout 而应该以设定间隔发生的动画时,我调用 clearQueue() 它将摆脱任何其他已设置发生的动画。然后我会调用动画。这样,当您返回该选项卡时,您就不会将所有这些动画排队,它会变得疯狂。最多只能设置一个。

    所以是这样的:

           spotlight.timeOutSpotlight = setTimeout(function () {
                spotlight.clearQueue(); // get rid of other instances of the animation
                spotlight.animate(spotlight.i);
            }, 8000);
    

    它可能并非在所有情况下都有效(取决于时间),但我希望对某人有所帮助!

    【讨论】:

    • 我上面的答案更正确,但如果你已经有大量依赖于该超时的函数,则可能很难做到。
    【解决方案5】:

    你一定也认为你使用了 clearTimeout。

    当您调用 setTimeout 函数时,它会返回一个 ID,您可以将此 ID 保存在变量中,例如

    timeoutID = setTimeout(function () {
                    spotlight.animate(spotlight.i);
                }, 8000);
    

    在设置新的超时之前,您可以像这样调用函数

    clearTimeout(timeoutID)
    

    【讨论】:

      【解决方案6】:

      我的怀疑是浏览器将诸如“点击”之类的输入事件排入队列,但仅在事件发生的选项卡实际具有焦点时才会触发它们。

      也许你应该尝试直接调用你的点击回调而不是使用trigger('click')

      类似这样的:

      spotlight: {
          i: 0,
         timeOutSpotlight: null,
         clickFunc: function(element) {
      
             // do stuff here to count and move images
      
             // Clear timeout
             clearTimeout(spotlight.timeOutSpotlight);
      
             // Some stuff here to calculate next item
      
             // Call next spotlight in 8 seconds
             spotlight.timeOutSpotlight = setTimeout(function () {
                  spotlight.animate(spotlight.i);
             }, 8000);
         },
      
         init: function()
         {
      
             $('#spotlight .controls a').click(function (e) {
      
                 // Don't follow the link
                 e.preventDefault();
      
                 spotlight.clickFunc(this);
             });
      
             // Select first item
             spotlight.clickFunc($('#spotlight .controls a.next:first'));
         },
      
         animate: function(i)
         {
             var element = $('#spotlight .controls li:eq('+spotlight.i+') a.next');
             spotlight.clickFunc(element);
         }
      }
      

      【讨论】:

      • 我尝试了您的代码(顺便感谢您的撰写),但不幸的是结果仍然相同。不过,您可能会通过点击的触发来解决一些问题。我刚刚注意到滑块在一段时间后恢复到正常速度。看起来浏览器确实在保存点击次数,直到您将注意力重新集中在选项卡上,然后它会一次运行所有点击次数。
      • 我刚刚检查了 console.log() 并且 setTimeout 在 clearTimeout 之前和之后返回了相同的数字。不知道为什么。也许这也与它有关?
      • 从日志数量来看,在我离开选项卡并返回后,控制台确实会继续记录这些消息。
      【解决方案7】:

      你运行的是什么版本的 jQuery?显然,这个问题在 1.6.3 版中已经“修复”了——他们恢复了导致这种情况发生的更改。讨论herehere

      虽然这个问题可能会在未来得到解决,但我们现在似乎已经摆脱了困境。

      【讨论】:

      • 这是个好消息。这是 jQuery 的早期版本,但我们应该记住 davydepauw 的回答,以防它再次出现。
      猜你喜欢
      • 1970-01-01
      • 2012-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-07
      相关资源
      最近更新 更多