ChatGPT解决这个技术问题 Extra ChatGPT

当标签或窗口不活动时,浏览器如何暂停/更改JavaScript?

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

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

当标签不活动时,ios 5暂停javascript

setInterval and setTimeout delay is reduced when tabs are not active - seems like this just started appearing recently and can mess up Jasmine unit tests, around other things.

当标签不活跃时,请求inimationframe会减慢(合理,无法想到为什么这会影响任何人)

我有以下问题:

除了移动浏览器,桌面浏览器是否会在选项卡不活动时暂停 JS 执行?何时以及哪些浏览器?

哪些浏览器减少了 setInterval 重复?它只是减少到一个限制还是一个百分比?例如,如果我有一个 10 毫秒的重复和一个 5000 毫秒的重复,每个都会受到什么影响?

如果窗口失焦,而不仅仅是选项卡,是否会发生这些变化? (我想它会更难检测,因为它需要 OS API。)

是否有其他在活动选项卡中不会观察到的效果?他们会不会把本来可以正确执行的事情搞砸(即前面提到的 Jasmine 测试)?

如果它们被暂停,像 Facebook 这样的网站将不会在后台选项卡上收到任何聊天消息。
+1 这不会在任何地方发生,如果(某些)浏览器吸取了 setInterval 的优先级,我不会感到惊讶,但我怀疑它会产生很大的不同。
是的,没有暂停,但我记得读过当标签/窗口模糊时,1000 毫秒以下的 setInterval/setTimeout 时间更改为 1000 毫秒
当标签/窗口模糊时,@lan setInterval/setTimeout 次在 1000 毫秒以下更改为 1000 毫秒。不清楚你试图传达什么
+1 好问题。最好看到浏览器行为的并排比较,因为我相信标签不活动时的钳制行为不是任何标准的一部分。

A
Antony

测试一

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

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

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

测试二

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

测试 setInterval

测试 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

Firefox
与 Chrome 类似,当标签页(而非窗口)处于非活动状态时,Firefox 将 setInterval 的最小间隔限制为 1000 毫秒左右。但是,requestAnimationFrame在不活动的情况下,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
从 Edge 14 开始,setInterval 在非活动标签中的上限为 1000 毫秒。 requestAnimationFrame 始终在非活动标签中暂停。

Safari
与 Chrome 一样,当标签处于非活动状态时,Safari 会将 setInterval 的上限设为 1000 毫秒。 requestAnimationFrame 也被暂停。

Opera
由于采用了 Webkit 引擎,Opera 表现出与 Chrome 相同的行为。 setInterval 的上限为 1000 毫秒,requestAnimationFrame 在标签处于非活动状态时暂停。

概括

非活动标签的重复间隔:

setInterval     requestAnimationFrame
Chrome
9-         not affected    not supported
10         not affected    paused
11+        >=1000ms        paused

Firefox
3-         not affected    not supported
4          not affected    1s
5+         >=1000ms        2ns (n = number of frames since inactivity)

IE
9-         not affected    not supported
10+        not affected    paused

Edge
13-        not affected    paused
14+        >=1000ms        paused

Safari
5-         not affected    not supported
6          not affected    paused
7+         >=1000ms        paused

Opera
12-        not affected    not supported
15+        >=1000ms        paused

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

我观察到:在 Chrome 中的非活动标签页上,等待少于 1000 毫秒 的所有 setTimeout(对于 setInterval 必须相同)四舍五入到 1000 毫秒。我认为更长的超时不会被修改。

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

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


jQuery 的 focusblur 事件似乎检测到选项卡和窗口切换,因此可以想象它可以双向工作。但我想知道窗口如何检测它是否真的可见。
实际上它与 jQuery 或 Javascript 无关,因为它是内部浏览器实现。
您现在可以在 2016 年末确认这一点吗?
G
Gershom Maes

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

让超时 = [ 500, 1000, 2000, 3000, 10000 ];让 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(); 让 disp = document.createElement('p'); 让 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,小姐); });正文 { 字体大小:80%; } div { 最大高度:80px;溢出-x:自动;背景色:rgba(0, 0, 0, 0.1);边距底部:2px;空白:nowrap; } p { 边距:0; } div > p { 边距:0;显示:内联块;垂直对齐:顶部;右边距:2px; } 输入 { 边距:0 0 10px 0; } .t500:before { 显示:块;内容:'500ms';字体粗细:粗体; } .t1000:之前 { 显示:块;内容:'1000ms';字体粗细:粗体; } .t2000:之前 { 显示:块;内容:'2000ms';字体粗细:粗体; } .t3000:之前 { 显示:块;内容:'3000ms';字体粗细:粗体; } .t10000:之前 { 显示:块;内容:'10000ms';字体粗细:粗体; }

忽略任何延迟小于此数量的值:

< div class="timeout t500">