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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15871942/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 02:23:43  来源:igfitidea点击:

How do browsers pause/change Javascript when tab or window is not active?

javascriptbrowser

提问by Andrew Mao

Background: I'm doing some user interface tests that need to detect if people are paying attention or not. But, this question is notabout the page visibility API.

背景:我正在做一些用户界面测试,需要检测人们是否在关注。但是,这个问题是不是有关的页面知名度API

Specifically, I would like to know how my Javascript code will be affected if the current tab is not active, or the browser window is not active, in different browsers. I've dug up the following so far:

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

I have the following questions:

我有以下问题:

  • Other than mobile browsers, do desktop browsers ever pause JS execution when a tab is not active? When and which browsers?
  • Which browsers reduce the setIntervalrepeat? Is it just reduced to a limit or by a percentage? For example, if I have a 10ms repeat versus a 5000ms repeat, how will each be affected?
  • Do these changes happen if the windowis out of focus, as opposed to just the tab? (I imagine it would be harder to detect, as it requires the OS API.)
  • Are there any other effects that would not be observed in an active tab? Could they mess things up that would otherwise execute correctly (i.e. the aforementioned Jasmine tests)?
  • 除了移动浏览器,桌面浏览器是否会在选项卡不活动时暂停 JS 执行?何时使用哪些浏览器?
  • 哪些浏览器减少了setInterval重复?它只是减少到一个限制还是一个百分比?例如,如果我有 10 毫秒的重复和 5000 毫秒的重复,那么每个重复会受到什么影响?
  • 如果窗口失焦,而不仅仅是选项卡,是否会发生这些变化?(我想它会更难检测,因为它需要 OS API。)
  • 在活动选项卡中是否有任何其他效果不会被观察到?他们会不会把本来可以正确执行的事情搞砸(即前面提到的 Jasmine 测试)?

回答by Antony

Test One

测试一

I have written a test specifically for this purpose:
Frame Rate Distribution: setInterval vs requestAnimationFrame

我为此专门编写了一个测试:
帧速率分布:setInterval vs requestAnimationFrame

Note: This test is quite CPU intensive. requestAnimationFrameis not supported by IE 9- and Opera 12-.

注意:此测试非常占用 CPU。requestAnimationFrameIE 9- 和 Opera 12- 不支持。

The test logs the actual time it takes for a setIntervaland requestAnimationFrameto run in different browsers, and gives you the results in the form of a distribution. You can change the number of milliseconds for setIntervalto see how it runs under different settings. setTimeoutworks similarly to a setIntervalwith respect to delays. requestAnimationFramegenerally defaults to the 60fps depending on the browser. To see what happens when you switch to a different tab or have an inactive window, simply open the page, switch to a different tab and wait for a while. It will continue to log the actual time it takes for these functions in an inactive tab.

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

Test Two

测试二

Another way to test it is to log the timestamp repeatedly with setIntervaland requestAnimationFrameand view it in a detached console. You can see how frequently it is updated (or if it is ever updated) when you make the tab or window inactive.

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

Results

结果

Chrome
Chrome limits the minimum interval of setIntervalto around 1000ms when the tab is inactive. If the interval is higher than 1000ms, it will run at the specified interval. It does not matter if the window is out of focus, the interval is limited only when you switch to a different tab. requestAnimationFrameis paused when the tab is inactive.

Chrome
ChromesetInterval将选项卡处于非活动状态时限制为大约1000ms的最小间隔。如果间隔大于 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

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

Firefox
Similar to Chrome, Firefox limits the minimum interval of setIntervalto around 1000ms when the tab (not the window) is inactive. However, requestAnimationFrameruns exponentially slower when the tab is inactive, with each frame taking 1s, 2s, 4s, 8s and so on.

Firefox
类似于Chrome,FirefoxsetInterval将标签(不是窗口)处于非活动状态时将最小间隔限制为大约1000ms。However, requestAnimationFrameruns exponentially slower when the tab is inactive, with each frame taking 1s, 2s, 4s, 8s and so on.

// 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

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

Internet Explorer
IE does not limit the delay in setIntervalwhen the tab is inactive, but it pauses requestAnimationFramein inactive tabs. It does not matter whether the window is out of focus or not.

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

Edge
Starting from Edge 14, setIntervalis capped at 1000ms in inactive tabs. requestAnimationFrameis always paused in inactive tabs.

Edge
从 Edge 14 开始,setInterval在非活动选项卡中的上限为 1000 毫秒。requestAnimationFrame在非活动选项卡中始终暂停。

Safari
Just like Chrome, Safari caps setIntervalat 1000ms when the tab is inactive. requestAnimationFrameis paused as well.

Safari
就像Chrome,setInterval当标签处于非活动状态时,Safari Caps在100毫秒时。requestAnimationFrame也暂停了。

Opera
Since the adoption of the Webkit engine, Opera exhibits the same behavior as Chrome. setIntervalis capped at 1000ms and requestAnimationFrameis paused when the tab is inactive.

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

Summary

概括

Repeating intervals for inactive tabs:

非活动选项卡的重复间隔:

           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

回答by Andrew Mao

What I observed : on inactive tabs in Chrome, all your setTimeout(must be the same for setInterval) waiting less than 1000msare rounded to 1000ms. I think longer timeouts are not modified.

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

Seems to be the behavior since Chrome 11and Firefox 5.0: https://developer.mozilla.org/en-US/docs/DOM/window.setTimeout#Inactive_tabs

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

Furthermore, I don't think it behaves this way when the whole window is inactive (but it seems quite easy to investigate).

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

回答by Gershom

A newer answer to complement these: on chrome 78.0.3904.108 I notice allof these timeouts (not just those below 1000ms) taking a bit longer than expected when I move to a different tab, and then come back. The behaviour I am seeing is more correctly described as "All timeouts on inactive tabs may be delayed by some additional amount, to a maximum of 1000ms.":

一个更新的答案来补充这些:在 chrome 78.0.3904.108 上,当我移动到不同的选项卡时,我注意到所有这些超时(不仅仅是那些低于 1000 毫秒的超时)花费的时间比预期的要长一些,然后又回来了。我看到的行为更准确地描述为“非活动选项卡上的所有超时可能会延迟一些额外的时间,最多为 1000 毫秒。”

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>