Chrome:超时/间隔在后台选项卡中暂停?

IT技术 javascript google-chrome tabs settimeout
2021-01-18 13:10:10

我正在测试setTimeout使用测试的准确性现在我注意到(正如预期的那样)setTimeout不是很准确,但对于大多数设备来说并不是非常不准确。现在,如果我在 Chrome 中运行测试并让它在后台选项卡中运行(因此,切换到另一个选项卡并在那里浏览),返回测试并检查结果(如果测试完成),它们会发生巨大变化。看起来超时的运行速度要慢得多。在 FF4 或 IE9 中测试没有发生这种情况。

因此,在没有焦点的选项卡中,Chrome 似乎暂停或至少减慢了 javascript 执行速度。在互联网上找不到关于该主题的太多内容。这意味着我们无法运行后台任务,例如使用 XHR 调用在服务器上定期检查,并且setInterval(我怀疑会看到相同的行为setInterval,如果有时间我会编写测试)。

有没有人遇到过这个?这种暂停/减速是否有解决方法?你会称它为错误吗,我应该这样提交吗?

6个回答

我最近问过这个问题,这是设计行为。When a tab is inactive, only at a maximum of once per second the function is called. 这是代码更改

也许这会有所帮助: 当 Chrome 中的选项卡处于非活动状态时,如何使 setInterval 也能工作?

TL;DR:使用Web Workers

@Kooilnc:没问题:) 我也不是以英语为母语的人。
2021-03-20 13:10:10
谢谢,我应该查看“非活动选项卡”。不是母语为英语的人有时是一个障碍。
2021-03-22 13:10:10
值得一提的是:“更新,2021 年 1 月:从 Chrome 88+ 开始,在某些情况下可以将计时器限制为 1 分钟。阅读更多有用的angle.com/web-updates/post/110/...
2021-04-06 13:10:10

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

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

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

http://github.com/turuslan/HackTimer

你是对的,但一些现代浏览器允许使用 Blob(html5rocks.com/en/tutorials/workers/basics/#toc-inlineworkers)在没有自己文件的情况下使用工人
2021-03-17 13:10:10
对于必须在前端运行的代码,例如,我们希望在做其他事情时完成的繁重图形处理任务呢?
2021-03-17 13:10:10
这很好,但请注意:1. 工作人员无法访问 DOM,2. 工作人员只有在他们自己处理文件时才会被执行。在很多情况下,不是setTimeout 的直接替代品。
2021-03-28 13:10:10
好吧,您可以使用 data-url 创建工作线程、服务工作线程并使用画布 API。new Worker('data:text/javascript,(' + function myWorkerCode () { /*...*/ } + '()'). 这也是检查是否有导入表达式支持的好方法:try { eval('import("data:text/javascript,void 0")') } catch (e) { /* no support! */ }
2021-04-02 13:10:10
即便如此,Web Workers 仍然缺少许多功能(即 DOM),这些功能允许它们成为 setTimeout 和 co 的安全替代品。
2021-04-03 13:10:10

播放 ~empty 声音会强制浏览器保持性能 - 我在阅读此评论后发现了这一点:即使选项卡未处于活动状态,如何使 JavaScript 在 Chrome 中以正常速度运行?

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

这是我为此目的创建的 2 个空音频循环,您可以在商业上自由使用它们:http : //adventure.land/sounds/loops/empty_loop_for_js_performance.ogg http://adventure.land/sounds/loops/empty_loop_for_js_performance.wav

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

我根据用户需求使用 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 劫持您的所有计算线程:|

不记得可能是复制粘贴的剩余部分,但是有一个声音限制和超过该限制的情人,浏览器只是忽略了声音 - 所以可能是这样
2021-03-28 13:10:10
谢谢,使用耳机时 58db 非常好听,但是将站点静音可以解决该问题
2021-04-01 13:10:10
为什么是 0.5?
2021-04-03 13:10:10
尝试使用 nosleep.js 获取如何为此使用视频的示例
2021-04-04 13:10:10

我已经发布了worker-interval 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

这是我的解决方案,它获取当前毫秒,并将其与创建函数的毫秒进行比较。对于间隔,它将在运行该函数时更新毫秒。您还可以通过 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>