使用 setInterval 时,如果我在 Chrome 中切换标签页并返回,滑块会疯狂追赶

IT技术 javascript jquery google-chrome slider
2021-02-25 12:01:12

我的网站上有一个 jQuery 滑块,下一张幻灯片的代码位于名为 nextImage 的函数中。我使用 setInterval 在计时器上运行我的函数,它完全符合我的要求:它在计时器上运行我的幻灯片。但是,如果我在 Chrome 中访问该站点,切换到另一个选项卡并返回,滑块会连续运行幻灯片,直到它“赶上”。有谁知道解决这个问题的方法。以下是我的代码。

setInterval(function() {
nextImage();
}, 8000);
6个回答

如何使用 Javascript 在 Chrome 中检测标签是否处于焦点状态?

window.addEventListener('focus', function() {
    document.title = 'focused';
},false);

window.addEventListener('blur', function() {
    document.title = 'not focused';
},false);

适用于您的情况:

var autopager;
function startAutopager() {
    autopager = window.setInterval(nextImage, 8000);
}
function stopAutopager() {
    window.clearInterval(autopager);
}

window.addEventListener('focus', startAutopager);    
window.addEventListener('blur', stopAutopager);

请注意,在最新版本的 Chromium 中,存在一个错误或“功能”使其不太可靠,要求用户至少在窗口中的任何地方单击一次。有关详细信息,请参阅上面的链接问题。

此处引用的答案已更新,给出的解决方案似乎不再适用,至少对我而言。什么做的工作是更新的答案的报价问题,这是使用visibilitychange事件,像这样:document.addEventListener('visibilitychange', function(){ document.title = document.hidden; })@ninjagecko 你能相应地更新答案吗?
2021-04-25 12:01:12
这是一个非常简单的解决方案,但我认为mousemove&touchmove处理程序更适合于此。因此,如果在给定的时间范围内选项卡内没有活动,则不应为该对象发出绿灯以尝试触发任何内容。
2021-05-11 12:01:12

我在这里发布了一个答案:当 Chrome 中的选项卡处于非活动状态时,如何使 setInterval 也能工作?

只需这样做:

setInterval(function() {
    $("#your-image-container").stop(true,true);
    nextImage();

}, 1000);

非活动浏览器选项卡会缓冲一些 setInterval 或 setTimeout 函数。stop(true,true) - 将停止所有缓冲事件并仅立即执行最后一个动画。

window.setTimeout() 方法现在限制为在非活动选项卡中每秒发送不超过一个超时。此外,它现在将嵌套超时限制为 HTML5 规范允许的最小值:4 毫秒(而不是它过去用于限制的 10 毫秒)。

谢谢 - 我到处寻找可以解决这个问题的东西,并且做到了。
2021-04-21 12:01:12

想到了几个想法:


想法#1

您可以使短脉冲具有幂等性例如,你可以说:

function now() {
    return (new Date()).getTime();
}

var autopagerInterval = 8000;

function startAutopager() {
    var startImage = getCurrentImageNumber();
    var startTime = now();

    var autopager = setInterval(
        function() {
            var timeSinceStart = now() - startTime();
            var targetImage = getCurrentImageNumber + Math.ceil(timeSinceStart/autopagerInterval);
            if (getCurrentImageNumber() != targetImage)
                setImageNumber(targetImage);  // trigger animation, etc.
        },
        autopagerInterval
    );
    return autopager;
}

这样即使函数运行了 1000 次,它仍然会在几毫秒内运行并且只动画一次。

注意:如果用户离开页面并返回,它将滚动。这可能不是原始海报想要的,但我留下这个解决方案,因为它有时是你想要的。


想法#2

添加幂等性的另一种方法(同时仍然保持您的nextImage()函数并且不让它滚动到页面底部)是让函数设置一个互斥锁,该锁在一秒钟后消失(由另一个超时清除)。因此,即使 setInterval 函数被调用 1000 次,也只有第一个实例会运行,其他实例什么也不做。

var locked = false;
var autopager = window.setInterval(function(){
    if (!locked) {
        locked = true;
        window.setTimeout(function(){
            locked=false;
        }, 1000);
        nextImage();
    }
}, 8000);

编辑:这可能不起作用,见下文


想法#3

我尝试了以下测试:

function f() {
    console.log((new Date()) + window.focus());
    window.setTimeout(f, 1000);
}
f();

它似乎表明该函数每秒被调用一次。这很奇怪......但我认为这意味着回调被调用,但该页面渲染拒绝任何图形化的方式来更新页面,而标签是没有重点,延缓所有的操作,直到用户返回,但操作保持打桩向上。

window.focus()函数也不会说明窗口是否具有焦点;它将焦点放在窗口上,因此无关紧要。

我们想要的可能是这样的:如何使用 Javascript 检测 Chrome 中的选项卡何时聚焦或不聚焦?-- 您可以在窗口失去焦点(模糊)时取消设置间隔,并在获得焦点时重置间隔。

@Nathan:我的第二个想法(更新)可能有效,而且更短,我有第三个想法
2021-04-19 12:01:12
我在哪里调用我的 nextImage 函数?
2021-05-01 12:01:12
如果if (!window.focus)解决方案有效,它绝对优于这个解决方案,特别是因为我认为用户返回并发现页面一直向下滚动并不是您的意图
2021-05-02 12:01:12
你会有一个功能setImageNumber(num)而不是nextImage = function(){setImageNumber(getCurrentImageNumber()+1)}
2021-05-08 12:01:12
不幸的是 window.focus 解决方案不起作用。我真的希望它很简单。令人讨厌的是,它在所有其他浏览器中都可以正常工作,并且只需要一行代码。我希望我也可以让它在 Chrome 中工作而不需要很多额外的代码。
2021-05-10 12:01:12

我不知道你的函数 nextImage() 到底发生了什么,但我遇到了类似的问题。我在我创建的 jQuery 图像滑块上使用 animate() 和 setInterval(),当我切换到不同的选项卡并再次返回时,我遇到了与您相同的事情。在我的例子中 animate() 函数正在排队,所以一旦窗口重新获得焦点,滑块就会发疯。为了解决这个问题,我只是停止了 animate() 函数的排队。

有几种方法可以做到这一点。最简单的方法是使用 .stop(),但是这个问题和修复它的方法记录在 jQuery 文档中。在标题附加说明下检查底部附近的此页面:http : //api.jquery.com/animate/

我遇到过类似的问题,不知何故,下面的代码对我来说很好用。

            var t1= window.setInterval('autoScroll()', 8000);

    window.addEventListener('focus', function() {
        focused = true;
        window.clearInterval(t1);
        t1 = window.setInterval('autoScroll()', 8000);
    },false);

    window.addEventListener('blur', function() {
        focused = false;
        window.clearInterval(t1);
    },false)



function autoScroll()

    {

        if ( running == true){
            if ( focused = true){
                forwardSlide();
            }


        }

        else {

            running = true;

        }



    }
您的超时值为 8000 毫秒,因此您不会受到此问题的影响(无需解决方法)。Chrome允许SetInteVal在选项卡没有焦点时每1000毫秒调用每1000ms。
2021-05-01 12:01:12