背景:我正在做一些需要检测人们是否注意的用户界面测试。但是,关于the page visibility API,这个问题不。
具体来说,我想知道如果当前选项卡未激活,或者浏览器窗口未处于活动状态,我的Javascript代码将在不同的浏览器中受到影响。到目前为止,我已经挖出了以下内容:
setInterval
and setTimeout
delay is reduced when tabs are not active - 似乎最近刚刚开始出现,并且可能会破坏Jasmine单元测试,围绕其他事情。requestAnimationFrame
速度变慢(合理,无法想到为什么这会对任何人造成太大影响)我有以下问题:
setInterval
重复?它只是减少到一个限度或一个百分比?例如,如果我有10毫秒重复而不是5000毫秒重复,那么每个都会受到影响吗?答案 0 :(得分:172)
我专门为此目的编写了一个测试:
Frame Rate Distribution: setInterval vs requestAnimationFrame
注意:此测试非常占用CPU。 IE 9-和Opera 12不支持requestAnimationFrame
。
测试记录了setInterval
和requestAnimationFrame
在不同浏览器中运行所需的实际时间,并以分发的形式提供结果。您可以更改setInterval
的毫秒数,以查看它在不同设置下的运行方式。关于延迟,setTimeout
与setInterval
的工作方式类似。 requestAnimationFrame
通常默认为60fps,具体取决于浏览器。要查看切换到其他选项卡或具有非活动窗口时会发生什么,只需打开页面,切换到其他选项卡并等待一段时间。它将继续记录这些函数在非活动选项卡中所需的实际时间。
测试它的另一种方法是使用setInterval
和requestAnimationFrame
重复记录时间戳,并在分离的控制台中查看它。当您使选项卡或窗口处于非活动状态时,您可以查看更新频率(或更新时间)。
<强>铬强>
当标签处于非活动状态时,Chrome会将setInterval
的最小间隔限制为大约1000毫秒。如果间隔高于1000毫秒,它将以指定的间隔运行。窗口是否失焦并不重要,只有当您切换到不同的选项卡时才会限制间隔。选项卡处于非活动状态时,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
的最小间隔限制为大约1000毫秒。但是,当选项卡处于非活动状态时,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
。窗口是否失焦并不重要。
<强>边强>
从边缘14开始,setInterval
在非活动选项卡中的上限为1000毫秒。 requestAnimationFrame
始终在非活动标签页中暂停。
<强> Safari浏览器强>
就像Chrome一样,当标签处于非活动状态时,Safari会在1000毫秒时限制setInterval
。 requestAnimationFrame
也暂停了。
<强>戏强>
自从采用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
答案 1 :(得分:10)
我观察到:在 Chrome 中的非活动标签页上,等待 1000毫秒的所有setTimeout
(setInterval
必须相同)四舍五入到 1000毫秒。我认为更长的超时时间不会被修改。
似乎是 Chrome 11 和 Firefox 5.0 之后的行为:https://developer.mozilla.org/en-US/docs/DOM/window.setTimeout#Inactive_tabs
此外,当整个窗口处于非活动状态时,我认为它不会这样(但似乎很容易调查)。
答案 2 :(得分:0)
一个新的答案来补充这些问题:在Chrome 78.0.3904.108上,我注意到所有所有超时(不仅限于1000ms以下的超时)比我移至其他标签页所花费的时间长于预期,并且然后回来。我看到的行为被更正确地描述为“非活动标签上的所有超时都可能会延迟一些额外的时间,最长为1000ms。” :
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>