当选项卡或窗口不活动时,浏览器如何暂停/更改Javascript
How do browsers pause/change Javascript when tab or window is not active?
背景:我正在做一些用户界面测试,需要检测人们是否在关注。但是,这个问题是而不是关于页面可见性API。
具体来说,我想知道我的Javascript代码将如何受到影响,如果当前选项卡不活跃,或浏览器窗口不活跃,在不同的浏览器。到目前为止,我已经找到了以下内容:
- ios 5在tab未激活时暂停javascript
- 当标签不活动时,
setInterval
和setTimeout
延迟减少-似乎这只是最近才开始出现,并且可以弄乱Jasmine单元测试,围绕其他事情。 -
requestAnimationFrame
是慢的,当标签不活动(合理的,不能想到为什么这会影响任何人太多)
我有以下问题:
- 除了移动浏览器,桌面浏览器暂停JS执行时,标签不活动?什么时候用什么浏览器?
- 哪些浏览器减少了
setInterval
重复?它只是降低到一个极限还是一个百分比?例如,如果我有一个10ms的重复和一个5000ms的重复,它们将如何受到影响? - 如果窗口不在焦点上,是否会发生这些变化,而不仅仅是标签?(我想它会更难检测,因为它需要操作系统API。)
- 在活动选项卡中是否存在其他无法观察到的效果?它们会不会把本来可以正确执行的事情搞砸(比如前面提到的Jasmine测试)?
测试一
我为此专门编写了一个测试:
帧率分布:setInterval vs requestAnimationFrame
注意:这个测试是相当CPU密集的。IE 9-和Opera 12-不支持requestAnimationFrame
.
测试记录setInterval
和requestAnimationFrame
在不同浏览器中运行的实际时间,并以分布的形式给出结果。您可以更改setInterval
的毫秒数,以查看它在不同设置下的运行情况。setTimeout
与setInterval
在延迟方面的工作原理相似。requestAnimationFrame
通常默认为60fps,具体取决于浏览器。当你切换到不同的选项卡或有一个不活跃的窗口时,看看会发生什么,只需打开页面,切换到不同的选项卡并等待一段时间。它将继续在非活动选项卡中记录执行这些函数所需的实际时间。
测试2
另一种测试方法是使用setInterval
和requestAnimationFrame
重复记录时间戳,并在分离的控制台中查看它。当你使选项卡或窗口处于非活动状态时,你可以看到它更新的频率(或者它是否曾经更新过)。
-
setInterval
测试 -
requestAnimationFrame
测试
当标签处于非活动状态时,Chrome限制setInterval
的最小间隔为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 一口>
Firefox
与Chrome类似,当选项卡(不是窗口)处于非活动状态时,Firefox将setInterval
的最小间隔限制在1000ms左右。然而,当选项卡处于非活动状态时,requestAnimationFrame
的运行速度会呈指数级下降,每帧需要15、25、45、8秒等等。
// 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
在非活动选项卡中的上限为1000ms。requestAnimationFrame
总是在非活动选项卡中暂停。
Safari
就像Chrome一样,当标签处于非活动状态时,Safari将setInterval
设置为1000ms。requestAnimationFrame
也暂停了。
由于采用Webkit引擎,Opera表现出与Chrome相同的行为。setInterval
的上限为1000ms, requestAnimationFrame
在选项卡不活动时暂停。
非活动选项卡的重复间隔:
<>之前 setInterval requestAnimationFrame 铬不受影响,不支持10不受影响暂停11+>=1000ms暂停Firefox 3-不受影响不支持4个不受影响5+>=1000ms 2ns (n =静止帧数)IE 不受影响,不支持10+不受影响暂停边缘13-不受影响,暂停14+>=1000ms暂停 Safari 不受影响,不支持6不受影响暂停7+>=1000ms暂停歌剧不受影响,不支持15+>=1000ms暂停我观察到:在Chrome中的非活动选项卡上,所有setTimeout
(必须与setInterval
相同)等待少于1000ms被舍入到1000ms。我认为更长的超时时间没有修改。
似乎是自Chrome 11和Firefox 5.0: https://developer.mozilla.org/en-US/docs/DOM/window.setTimeout#Inactive_tabs
以来的行为此外,我不认为它的行为,当整个窗口是非活动的(但它似乎很容易调查)。
一个更新的答案来补充这些:在chrome 78.0.3904.108上,我注意到所有的这些超时(不仅仅是那些低于1000ms)比预期的要长一点,当我移动到不同的标签,然后回来。我看到的行为更准确地描述为"所有非活动选项卡上的超时可能会延迟一些额外的量,最多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>
- 如何临时暂停浏览器渲染,然后恢复整个页面
- jQuery循环在特定位置暂停
- NodeJS-readline暂停和恢复事件发射器(逐行读取)
- 最小化时暂停Javascript动画
- jQuery:暂停按钮可以暂停所有其他操作
- tiltSlider播放/暂停视频元素(如果li有当前类)
- Canvas+svg路径动画,在路径中的特定点暂停一段时间,然后继续
- CSS动画暂停并使用javascript播放
- 如何暂停和恢复jquery间隔
- 如何在隐藏时暂停jquery计时器
- 具体化:如何只使用HTML和Javascript制作播放/暂停按钮
- 在 jquery 中定位暂停和播放按钮
- 暂停文档-HTML、CSS、JavaScript
- 如何在悬停时暂停setInterval
- 暂停函数执行流程,直到ajax请求完成
- 使用javascript和随机暂停/超时快速循环文本
- 如何暂停网页
- HTML5画布-暂停时的运行时间
- 避免在钛合金加速器中暂停应用程序
- 我的HTML5游戏不时暂停,我如何才能知道它是否's是由垃圾收集引起的