Chrome: 后台标签中的超时/间隔暂停?

我在用 这个测试测试 setTimeout的准确性。现在我注意到(正如预期的那样) setTimeout不是很精确,但是对于大多数电器来说并不是非常不精确。现在,如果我在 Chrome 中运行测试并让它在一个后台选项卡中运行(所以,切换到另一个选项卡并在那里浏览) ,返回到测试并检查结果(如果测试结束) ,它们将发生显著变化。看起来超时的速度慢了很多。在 FF4或 IE9测试中没有出现这种情况。

所以看起来 Chrome 在一个没有焦点的选项卡中暂停或者至少减慢了 javascript 的执行。在网上找不到这方面的资料。这将意味着我们不能运行后台任务,例如,使用 XHR 调用和 setInterval在服务器上定期检查(我怀疑在 setInterval上看到同样的行为,如果时间和我在一起,就会编写一个测试)。

有人遇到过这种情况吗?这种悬挂/减速有什么变通办法吗?你会称之为错误吗? 我应该这样归档吗?

135533 次浏览

我最近问过这个问题,这是设计好的行为。当选项卡处于非活动状态时,最多每秒调用一次函数。这是 代码改变

也许这会有所帮助: 如何让 setInterval 在 Chrome 中标签页处于非活动状态时也能工作?

使用 网络工作者

我将 jQuery 核心更新为1.9.1,它解决了非活动选项卡中的间隔差异。我会先尝试,然后看看其他代码覆盖选项。

有一个使用 WebWorkers 的解决方案,因为它们在单独的进程中运行,并且不会减慢速度

我编写了一个小脚本,可以在不改变代码的情况下使用——它只是覆盖了 setTimeout、 clearTimeout、 setInterval、 clearInterval 等函数

只要在所有代码之前包含它

Http://github.com/turuslan/hacktimer

我已经发布了 工人间隔 npm 包,其中 setInterval 和 clearInterval 的实现使用 Web-Workers 来保持和运行 Chrome、 Firefox 和 IE 的非活动标签。

大多数现代的浏览器(Chrome,Firefox 和 IE) ,间隔(窗口计时器)都被限制在非活动标签中每秒最多触发一次。

你可以找到更多关于

Https://developer.mozilla.org/en-us/docs/web/api/windoworworkerglobalscope/setinterval

Https://developer.mozilla.org/en-us/docs/web/api/web_workers_api/using_web_workers#timeouts_and_intervals

播放一个空的声音迫使浏览器保持性能

对于 在这里找到这个评论的来源:

Chromium 内部人员还澄清说,对于所有“播放音频”的后台选项卡以及任何存在“活动 websocket 连接”的页面,将自动禁用激进的节流

对于使用 WebSocket 的浏览器游戏,我需要无限制的按需性能,所以我从经验中知道,使用 WebSocket 并不能确保无限制的性能,但是通过测试,播放音频文件似乎可以确保无限制的性能

下面是我为此创建的两个空的音频循环,你可以自由地使用它们,商业化地使用: Http://adventure.land/sounds/loops/empty_loop_for_js_performance.ogg Http://adventure.land/sounds/loops/empty_loop_for_js_performance.wav

(它们包括 -58分贝的噪音,-60分贝的噪音不起作用)

我使用 Howler.js: https://github.com/goldfire/howler.js根据用户需要播放它们

function performance_trick()
{
if(sounds.empty) return sounds.empty.play();
sounds.empty = new Howl({
src: ['/sounds/loops/empty_loop_for_js_performance.ogg','/sounds/loops/empty_loop_for_js_performance.wav'],
volume:0.5,
autoplay: true, loop: true,
});
}

遗憾的是,缺省情况下没有内置的方法来打开/关闭完整的 JavaScript 性能,然而,加密挖掘者可以在没有任何提示的情况下使用 Web Workers 劫持您所有的计算线程。

这是我的解决方案,它获取当前的毫秒,并将其与创建函数的毫秒进行比较。对于间隔,它将在运行函数时更新毫秒。您还可以通过 id 获取间隔/超时。

<script>


var nowMillisTimeout = [];
var timeout = [];
var nowMillisInterval = [];
var interval = [];


function getCurrentMillis(){
var d = new Date();
var now = d.getHours()+""+d.getMinutes()+""+d.getSeconds()+""+d.getMilliseconds();
return now;
}


function setAccurateTimeout(callbackfunction, millis, id=0){
nowMillisTimeout[id] = getCurrentMillis();
timeout[id] = setInterval(function(){ var now = getCurrentMillis(); if(now >= (+nowMillisTimeout[id] + +millis)){callbackfunction.call(); clearInterval(timeout[id]);} }, 10);
}


function setAccurateInterval(callbackfunction, millis, id=0){
nowMillisInterval[id] = getCurrentMillis();
interval[id] = setInterval(function(){ var now = getCurrentMillis(); if(now >= (+nowMillisInterval[id] + +millis)){callbackfunction.call(); nowMillisInterval[id] = getCurrentMillis();} }, 10);
}


//usage
setAccurateTimeout(function(){ console.log('test timeout'); }, 1000, 1);


setAccurateInterval(function(){ console.log('test interval'); }, 1000, 1);


</script>

对于单元测试,可以使用参数 --disable-background-timer-throttling运行 chrome/chromium