浏览器如何暂停/更改JavaScript时选项卡或窗口未激活?

Posted

技术标签:

【中文标题】浏览器如何暂停/更改JavaScript时选项卡或窗口未激活?【英文标题】:How do browsers pause/change Javascript when tab or window is not active? 【发布时间】:2013-03-30 02:41:52 【问题描述】:

背景:我正在做一些用户界面测试,需要检测人们是否在注意。但是,这个问题不是关于the page visibility API。

具体来说,我想知道如果当前选项卡不活动,或者浏览器窗口不活动,在不同的浏览器中,我的 javascript 代码将如何受到影响。到目前为止,我已经挖掘了以下内容:

ios 5 pauses javascript when tab is not active setInterval and setTimeout delay is reduced when tabs are not active - 这似乎是最近才开始出现的,并且可能会在其他事情上弄乱 Jasmine 单元测试。 requestAnimationFrame 在标签不活动时变慢(合理,想不出为什么这会对任何人造成太大影响)

我有以下问题:

除了移动浏览器,桌面浏览器是否会在选项卡不活动时暂停 JS 执行?何时使用哪些浏览器? 哪些浏览器减少了setInterval 重复?它只是减少到一个限制还是一个百分比?例如,如果我有 10 毫秒的重复和 5000 毫秒的重复,它们会受到怎样的影响? 如果窗口 失焦,而不仅仅是标签,是否会发生这些变化? (我想它会更难检测,因为它需要 OS API。) 是否还有其他在活动选项卡中无法观察到的效果?他们会不会把本来可以正确执行的事情搞砸(即前面提到的 Jasmine 测试)?

【问题讨论】:

如果它们被暂停,像 Facebook 这样的网站将不会在后台选项卡上收到任何聊天消息。 是的,没有暂停,但我记得读取的setInterval 987654328 setTimeout 987654329 setTimeout 987654329 @ ince in 1000ms的@次在选项卡/窗口模糊时更改为1000ms span> @ProfPickle 网站管理员?真的吗?这是一道 JS 编程题。 @lan setInterval/setTimeout 当标签/窗口模糊时,1000ms 以下的时间更改为 1000ms。不清楚你试图传达什么 +1 好问题。最好看到浏览器行为的并排比较,因为我相信标签不活动时的钳制行为不是任何标准的一部分。 【参考方案1】:

测试一

我为此专门编写了一个测试:Frame Rate Distribution: setInterval vs requestAnimationFrame

注意:此测试占用大量 CPU。 IE 9- 和 Opera 12- 不支持requestAnimationFrame

测试记录setIntervalrequestAnimationFrame 在不同浏览器中运行的实际时间,并以分布的形式为您提供结果。您可以更改setInterval 的毫秒数,以查看它在不同设置下的运行情况。 setTimeout 在延迟方面与 setInterval 的工作方式类似。 requestAnimationFrame 通常默认为 60fps,具体取决于浏览器。要查看当您切换到其他选项卡或有一个非活动窗口时会发生什么,只需打开页面,切换到其他选项卡并等待一段时间。它将继续在非活动选项卡中记录这些功能所花费的实际时间。

测试二

另一种测试方法是使用setIntervalrequestAnimationFrame 重复记录时间戳,并在分离的控制台中查看。当您使选项卡或窗口处于非活动状态时,您可以查看它的更新频率(或是否曾经更新)。

Test for setInterval Test for requestAnimationFrame

结果

Chrome 当标签页处于非活动状态时,Chrome 将 setInterval 的最小间隔限制为 1000 毫秒左右。如果间隔高于 1000ms,它将以指定的间隔运行。窗口是否失焦无关紧要,仅当您切换到不同的选项卡时,间隔才会受到限制。当标签页处于非活动状态时,requestAnimationFrame 会暂停。

// Provides control over the minimum timer interval for background tabs.
const double kBackgroundTabTimerInterval = 1.0;

https://codereview.chromium.org/6546021/patch/1001/2001

火狐 类似于Chrome,Firefox将setInterval的最小间隔限制为setInterval当标签(不是窗口)处于非活动状态时约1000ms。但是,requestAnimationFrame 在标签页处于非活动状态时运行速度会呈指数级下降,每一帧需要 1s、2s、4s、8s 等等。

// The default shortest interval/timeout we permit
#define DEFAULT_MIN_TIMEOUT_VALUE 4 // 4ms
#define DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE 1000 // 1000ms

https://hg.mozilla.org/releases/mozilla-release/file/0bf1cadfb004/dom/base/nsGlobalWindow.cpp#l296

Internet Explorer 当标签页处于非活动状态时,IE 不会限制 setInterval 的延迟,但会在非活动标签页中暂停 requestAnimationFrame。窗口是否失焦并不重要。

边缘 从 Edge 14 开始,setInterval 在非活动选项卡中的上限为 1000 毫秒。 requestAnimationFrame 总是在非活动标签中暂停。

Safari 就像 Chrome 一样,当标签页处于非活动状态时,Safari 将 setInterval 设置为 1000 毫秒。 requestAnimationFrame 也已暂停。

歌剧 自从采用 Webkit 引擎以来,Opera 表现出与 Chrome 相同的行为。 setInterval 的上限为 1000 毫秒,requestAnimationFrame 在选项卡处于非活动状态时暂停。

总结

非活动标签的重复间隔:

setInterval requestAnimationFrame 9- 不受影响 不支持 10 不受影响暂停 11+ >=1000ms 暂停 火狐 3- 不受影响 不支持 4 不受影响 1s 5+ >=1000ms 2ns(n = 自不活动以来的帧数) IE 9- 不受影响 不支持 10+ 不受影响已暂停 边缘 13-不受影响暂停 14+ >=1000ms 暂停 野生动物园 5- 不受影响 不支持 6 不受影响 暂停 7+ >=1000ms 暂停 歌剧 12- 不受影响 不支持 15+ >=1000ms 暂停

【讨论】:

很好的答案。除了setIntervalrequestAnimationFrame 之外的函数还有其他可能的已知差异吗? @AndrewMao 我不知道。我在开发一个库以可靠地检测是否使用setIntervalrequestAnimationFrame 重新启用了 JS 时遇到了这个问题。我知道setTimeout 的行为类似于setInterval,因为它们在Firefox 和Chrome 中具有相同的最小背景间隔,而在其他浏览器中没有明显限制。 显然可以通过在浏览器中打开 url about:config 并将 dom.min_background_timeout_value 值更改为 1000 以外的值来更改 Firefox setInterval 最小值。 当浏览器最小化时,我可以使用它每 5 秒重新加载一次页面吗?here 是我的问题。 请注意,如果用户只是切换应用程序(Alt+Tab 退出 Chrome),chrome 不会暂停/降低调用 requestAnimationFrame 的速率。只要标签在 Chrome 中处于活动状态,“帧速率”就或多或少是恒定的。【参考方案2】:

我观察到:在 Chrome 中的非活动选项卡上,等待小于 1000 毫秒 的所有 setTimeoutsetInterval 必须相同)被四舍五入为 1000 毫秒。我认为不会修改更长的超时时间。

似乎是自 Chrome 11Firefox 5.0 以来的行为:https://developer.mozilla.org/en-US/docs/DOM/window.setTimeout#Inactive_tabs

此外,当整个窗口处于非活动状态时,我认为它不会以这种方式运行(但似乎很容易调查)。

【讨论】:

jQuery 的 focusblur 事件似乎检测到选项卡和窗口切换,因此可以想象它可以双向工作。但我想知道窗口如何检测它是否真的可见。 其实它和 jQueryJavascript 没有任何关系,因为它是内部浏览器实现。 你能在 2016 年底确认吗?【参考方案3】:

一个更新的答案来补充这些:在 chrome 78.0.3904.108 上,当我移动到不同的选项卡时,我注意到所有这些超时(不仅仅是那些低于 1000 毫秒的超时)比预期的要长一些,并且然后回来。我看到的行为更正确地描述为 “非活动选项卡上的所有超时可能会延迟一些额外的量,最多 1000 毫秒。” 尝试运行以下命令并切换到另一个选项卡! p>

let timeouts = [ 500, 1000, 2000, 3000, 10000 ];

let minExcess = document.getElementsByClassName('minExcess')[0];

timeouts.forEach(ms => 
  let elem = document.getElementsByClassName(`t$ms`)[0];
  let cnt = 0;
  
  let lastMs = +new Date();
  let f = () => 
    let curMs = +new Date();
    let disp = document.createElement('p');
    let net = curMs - lastMs;
    lastMs = curMs;
        
    setTimeout(f, ms);
    if (minExcess.value && (net - ms) < parseInt(minExcess.value)) return;
    
    disp.innerText = `$net,`;
    elem.appendChild(disp);
    if (++cnt > 10) elem.firstElementChild.remove();
    
  ;
  setTimeout(f, ms);
  
);
body  font-size: 80%; 
div 
  max-height: 80px;
  overflow-x: auto;
  background-color: rgba(0, 0, 0, 0.1);
  margin-bottom: 2px;
  white-space: nowrap;

p  margin: 0; 
div > p 
  margin: 0;
  display: inline-block;
  vertical-align: top;
  margin-right: 2px;

input  margin: 0 0 10px 0; 
.t500:before  display: block; content: '500ms'; font-weight: bold; 
.t1000:before  display: block; content: '1000ms'; font-weight: bold; 
.t2000:before  display: block; content: '2000ms'; font-weight: bold; 
.t3000:before  display: block; content: '3000ms'; font-weight: bold; 
.t10000:before  display: block; content: '10000ms'; font-weight: bold; 
<p>Ignore any values delayed by less than this amount:</p>
<input type="text" class="minExcess" value="200" pattern="^[0-9]*$"/>
<div class="timeout t500"></div>
<div class="timeout t1000"></div>
<div class="timeout t2000"></div>
<div class="timeout t3000"></div>
<div class="timeout t10000"></div>

【讨论】:

以上是关于浏览器如何暂停/更改JavaScript时选项卡或窗口未激活?的主要内容,如果未能解决你的问题,请参考以下文章

使用 CodeceptJS 时如何打开新选项卡或窗口

如何自定义 android 选项卡或背景更改?

javascript 当用户激活另一个选项卡或窗口时触发事件

手风琴选项卡更改暂停视频

窗口最小化时 HTML 视频暂停

蓝牙 LE 在暂停时断开连接