我有一个setInterval,每秒运行一段代码30次。这工作得很好,但是当我选择另一个选项卡(使我的代码选项卡变得不活跃),setInterval由于某种原因被设置为空闲状态。

我制作了这个简化的测试用例(http://jsfiddle.net/7f6DX/3/):

var $div = $('div');
var a = 0;

setInterval(function() {
    a++;
    $div.css("left", a)
}, 1000 / 30);

如果您运行这段代码,然后切换到另一个选项卡,等待几秒钟并返回,动画将继续在切换到另一个选项卡时的位置。

因此,如果标签处于非活动状态,动画不会每秒运行30次。这可以通过计算每秒调用setInterval函数的次数来确认——如果选项卡处于非活动状态,这将不是30,而是1或2。

我想这样做是为了提高系统性能,但是有什么方法可以禁用这种行为吗?

这在我看来是劣势。


当前回答

这是一个很老的问题,但我遇到了同样的问题。

如果你在chrome上运行你的网页,你可以阅读这篇文章在chrome 57的背景标签。

基本上间隔计时器可以运行,如果它没有耗尽定时器预算。

预算的消耗基于计时器内任务的CPU时间使用情况。

基于我的场景,我将视频绘制到画布上并传输到WebRTC。

webrtc视频连接将保持更新,即使标签是不活跃的。

然而,你必须使用setInterval而不是requestAnimationFrame,但是itt不推荐用于UI渲染。

最好是监听visibilityChange事件并相应地改变渲染机制。

此外,您可以尝试Kaan Soral建议的方法,它应该可以根据文档工作。

其他回答

这是我的粗略解决方案

(function(){
var index = 1;
var intervals = {},
    timeouts = {};

function postMessageHandler(e) {
    window.postMessage('', "*");

    var now = new Date().getTime();

    sysFunc._each.call(timeouts, function(ind, obj) {
        var targetTime = obj[1];

        if (now >= targetTime) {
            obj[0]();
            delete timeouts[ind];
        }
    });
    sysFunc._each.call(intervals, function(ind, obj) {
        var startTime = obj[1];
        var func = obj[0];
        var ms = obj[2];

        if (now >= startTime + ms) {
            func();
            obj[1] = new Date().getTime();
        }
    });
}
window.addEventListener("message", postMessageHandler, true);
window.postMessage('', "*");

function _setTimeout(func, ms) {
    timeouts[index] = [func, new Date().getTime() + ms];
    return index++;
}

function _setInterval(func, ms) {
    intervals[index] = [func, new Date().getTime(), ms];
    return index++;
}

function _clearInterval(ind) {
    if (intervals[ind]) {
        delete intervals[ind]
    }
}
function _clearTimeout(ind) {
    if (timeouts[ind]) {
        delete timeouts[ind]
    }
}

var intervalIndex = _setInterval(function() {
    console.log('every 100ms');
}, 100);
_setTimeout(function() {
    console.log('run after 200ms');
}, 200);
_setTimeout(function() {
    console.log('closing the one that\'s 100ms');
    _clearInterval(intervalIndex)
}, 2000);

window._setTimeout = _setTimeout;
window._setInterval = _setInterval;
window._clearTimeout = _clearTimeout;
window._clearInterval = _clearInterval;
})();

只要这样做:

var $div = $('div');
var a = 0;

setInterval(function() {
    a++;
    $div.stop(true,true).css("left", a);
}, 1000 / 30);

不活跃的浏览器选项卡缓冲了一些setInterval或setTimeout函数。

Stop (true,true)将停止所有缓冲事件,并立即只执行最后一个动画。

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

受Ruslan Tushov图书馆的影响,我创建了自己的小型图书馆。只需在<head>中添加脚本,它将修补setInterval和setTimeout与那些使用WebWorker的。

有一个解决这个问题的方法,尽管实际上标签必须在某些窗口中被激活。

让你的非活动标签成为一个单独的浏览器窗口。 不要让任何其他窗口最大化(除非最大化的窗口在你的后面)。

这应该给浏览器一个始终处于活动状态的印象。

这有点麻烦,但也是一个快速的胜利。只要你能控制窗户的排列。

这是一个很老的问题,但我遇到了同样的问题。

如果你在chrome上运行你的网页,你可以阅读这篇文章在chrome 57的背景标签。

基本上间隔计时器可以运行,如果它没有耗尽定时器预算。

预算的消耗基于计时器内任务的CPU时间使用情况。

基于我的场景,我将视频绘制到画布上并传输到WebRTC。

webrtc视频连接将保持更新,即使标签是不活跃的。

然而,你必须使用setInterval而不是requestAnimationFrame,但是itt不推荐用于UI渲染。

最好是监听visibilityChange事件并相应地改变渲染机制。

此外,您可以尝试Kaan Soral建议的方法,它应该可以根据文档工作。