当Chrome中的标签页处于非活动状态时,如何使setInterval也起作用?

2020/10/19 05:01 · javascript ·  · 0评论

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。

我想这是设计使然,以提高性能,但是有什么办法可以禁用这种行为?在我的情况下,这实际上是一个缺点。

在大多数浏览器中,非活动选项卡的优先级较低,这可能会影响JavaScript计时器。

如果过渡的值是使用帧之间的实时时间而不是每个间隔的固定增量来计算的,那么您不仅可以解决此问题,而且可以通过使用requestAnimationFrame获得更流畅的动画,因为如果不使用处理器,它可以达到60fps很忙。

这是使用以下内容的动画属性转换的requestAnimationFrame原始JavaScript示例

var target = document.querySelector('div#target')
var startedAt, duration = 3000
var domain = [-100, window.innerWidth]
var range = domain[1] - domain[0]

function start() {
  startedAt = Date.now()
  updateTarget(0)
  requestAnimationFrame(update)
}

function update() {
  let elapsedTime = Date.now() - startedAt

  // playback is a value between 0 and 1
  // being 0 the start of the animation and 1 its end
  let playback = elapsedTime / duration

  updateTarget(playback)
  
  if (playback > 0 && playback < 1) {
  	// Queue the next frame
  	requestAnimationFrame(update)
  } else {
  	// Wait for a while and restart the animation
  	setTimeout(start, duration/10)
  }
}

function updateTarget(playback) {
  // Uncomment the line below to reverse the animation
  // playback = 1 - playback

  // Update the target properties based on the playback position
  let position = domain[0] + (playback * range)
  target.style.left = position + 'px'
  target.style.top = position + 'px'
  target.style.transform = 'scale(' + playback * 3 + ')'
}

start()
body {
  overflow: hidden;
}

div {
    position: absolute;
    white-space: nowrap;
}
<div id="target">...HERE WE GO</div>

对于后台任务(与UI无关)

@UpTheCreek评论:

适用于演示文稿问题,但仍然需要保持一些运行状态。

如果您有需要按给定间隔精确执行的后台任务,则可以使用HTML5 Web Workers有关更多详细信息,请查看下面的Möhre答案...

CSS vs JS“动画”

通过使用CSS过渡/动画而不是基于JavaScript的动画,可以避免此问题以及许多其他问题,这会增加相当大的开销。我建议使用这个jQuery插件,让您像animate()方法一样从CSS转换中受益

我在音频淡入和HTML5播放器中遇到了同样的问题。选项卡不活动时卡住了。因此,我发现WebWorker可以不受限制地使用间隔/超时。我用它来将“滴答”发布到主要的javascript。

WebWorkers代码:

var fading = false;
var interval;
self.addEventListener('message', function(e){
    switch (e.data) {
        case 'start':
            if (!fading){
                fading = true;
                interval = setInterval(function(){
                    self.postMessage('tick');
                }, 50);
            }
            break;
        case 'stop':
            clearInterval(interval);
            fading = false;
            break;
    };
}, false);

主要Javascript:

var player = new Audio();
player.fader = new Worker('js/fader.js');
player.faderPosition = 0.0;
player.faderTargetVolume = 1.0;
player.faderCallback = function(){};
player.fadeTo = function(volume, func){
    console.log('fadeTo called');
    if (func) this.faderCallback = func;
    this.faderTargetVolume = volume;
    this.fader.postMessage('start');
}
player.fader.addEventListener('message', function(e){
    console.log('fader tick');
    if (player.faderTargetVolume > player.volume){
        player.faderPosition -= 0.02;
    } else {
        player.faderPosition += 0.02;
    }
    var newVolume = Math.pow(player.faderPosition - 1, 2);
    if (newVolume > 0.999){
        player.volume = newVolume = 1.0;
        player.fader.postMessage('stop');
        player.faderCallback();
    } else if (newVolume < 0.001) {
        player.volume = newVolume = 0.0;
        player.fader.postMessage('stop');
        player.faderCallback();
    } else {
        player.volume = newVolume;
    }
});

有一个使用Web Workers的解决方案(如前所述),因为它们在单独的进程中运行并且不会减慢速度

我编写了一个很小的脚本,无需更改您的代码即可使用它-它只是覆盖了setTimeout,clearTimeout,setInterval,clearInterval函数。

只需在所有代码之前添加它即可。

更多信息在这里

只是这样做:

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

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

无效的浏览器标签会缓冲setIntervalsetTimeout功能中的某些功能。

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

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

我认为在此示例中对这个问题有最好的理解:http : //jsfiddle.net/TAHDb/

我在这里做一个简单的事情:

间隔1秒,每次隐藏第一个跨度并将其移动到最后一个,并显示第二个跨度。

如果您停留在页面上,它将按预期工作。但是,如果您将标签页隐藏了几秒钟,当您回来时,您会看到一个奇怪的东西。

就像所有在您处于非活动状态期间未发生的事件一样,现在将在一次时间内全部发生。所以几秒钟后,您将获得X事件。它们是如此之快,以至于可以一次看到所有6个跨度。

因此,它暗示了chrome仅会延迟事件,因此当您取回所有事件时,所有事件都会发生,但是所有事件都会一次出现。

这是一个简单的幻灯片演示的实际应用。想象一下数字是图像,如果用户回来时保持隐藏的选项卡,他将看到所有img浮动,完全混乱。

为了解决这个问题,请使用stop(true,true),如pimvdb所说。这将清除事件队列。

对我来说,像在这里播放其他音频一样在后台播放音频并不重要,我的问题是我有一些动画,当您在其他选项卡中又回到它们时,它们表现得很疯狂。我的解决办法是把里面这些动画如果这是预防活动标签

if (!document.hidden){ //your animation code here }

多亏了我的动画只有在选项卡处于活动状态时才运行我希望这会对我的案件有所帮助。

双方setIntervalrequestAnimationFrame没有工作的时候标签是不活动或工作,但不是在正确的时间。一种解决方案是使用其他事件源。例如,Web套接字Web Worker是两个事件源,它们在tab不活动时可以正常工作。因此,无需将所有代码移至Web Worker,只需将worker用作时间事件源即可:

// worker.js
setInterval(function() {
    postMessage('');
}, 1000 / 50);

var worker = new Worker('worker.js');
var t1 = 0;
worker.onmessage = function() {
    var t2 = new Date().getTime();
    console.log('fps =', 1000 / (t2 - t1) | 0);
    t1 = t2;
}

此示例的jsfiddle链接

在Ruslan Tushov的图书馆的影响下,我创建了自己的小型图书馆只需在中添加脚本,<head>它将使用setIntervalsetTimeout进行修补WebWorker

播放音频文件可确保暂时具有完整的后台Javascript性能

对我而言,这是最简单且干扰最小的解决方案-除了播放微弱/几乎空的声音外,没有其他潜在的副作用

您可以在此处找到详细信息:https : //stackoverflow.com/a/51191818/914546

(从其他答案中,我看到有些人使用Audio标签的不同属性,我确实想知道是否有可能在没有实际播放某些东西的情况下使用Audio标签来发挥全部性能)

注意:如果您希望间隔在背景上播放(例如播放音频或...),则此解决方案不适合,但是如果您对返回页面(标签)时动画无法正常播放感到困惑,这是一个好的解决方案。

有很多方法可以实现这一目标,也许“ WebWorkers”是最标准的方法,但是可以肯定,它不是最简单方便的方法,尤其是如果您没有足够的时间,可以尝试以下方法:

►基本概念:

1-为您的间隔(或动画)建立一个名称并设置间隔(动画),这样它将在用户首次打开您的页面时运行: var interval_id = setInterval(your_func, 3000);

2-通过$(window).focus(function() {});$(window).blur(function() {});您可以clearInterval(interval_id)每次停用浏览器(选项卡)并且每次重新运行间隔(动画)时,浏览器(选项卡)将再次激活interval_id = setInterval();

►样本代码:

var interval_id = setInterval(your_func, 3000);

$(window).focus(function() {
    interval_id = setInterval(your_func, 3000);
});
$(window).blur(function() {
    clearInterval(interval_id);
    interval_id = 0;
});

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

如果您在chrome上运行网络,则可以阅读
Chrome 57中的“背景标签”一文

基本上,如果间隔计时器没有超出计时器预算,则间隔计时器可以运行。

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


根据我的情况,我将视频绘制到画布上并传输到WebRTC。


即使选项卡处于非活动状态,webrtc视频连接也将不断更新。

但是,您必须使用setInterval而不是requestAnimationFrame

不过,建议不要将其用于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;
})();

我能够使用音频标签并处理其ontimeupdate事件至少在250ms内调用回调函数。一秒钟内调用3-4次。它比setTimeout滞后一秒要好

本文地址:http://javascript.askforanswer.com/dangchromezhongdebiaoqianyechuyufeihuodongzhuangtaishiruheshisetintervalyeqizuoyong.html
文章标签: ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!