requestAnimationFrame()不停止在Firefox当我离开选项卡?



https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame上的文档说:

requestAnimationFrame()调用在大多数浏览器中在后台选项卡中运行时暂停

background tab "的意思吗?当我从一个选项卡切换到另一个选项卡时,旧的选项卡会变成背景选项卡吗?如果是这样,那么下面的示例不会按照文档的方式运行。

在下面的例子中,我使用requestAnimationFrame()callback来记录回调调用的时间戳。当回调函数被调用时,它还会播放音频。

function playAudio() {
const ctx = new AudioContext();
const osc = ctx.createOscillator();
const startTime = ctx.currentTime;
const stopTime = startTime + 0.2;
osc.frequency.value = 440;
osc.connect(ctx.destination);
osc.start(startTime);
osc.stop(stopTime);
}
let lastActionTime = 0;
function action(timestamp) {
console.log(timestamp);
window.requestAnimationFrame(action);
if (timestamp - lastActionTime < 1000) {  // Throttle
return
}
playAudio()
lastActionTime = timestamp
}
function startAction() {
window.requestAnimationFrame(action);
}
window.onload = function() {
const startButton = document.getElementById("start");
startButton.addEventListener("click", startAction)
}
<button id="start">Start</button>

要运行此示例,请单击"开始"。按钮。每1秒开始播放一个音频音。现在切换到另一个选项卡。在Firefox中,我发现当我移到另一个选项卡时,音频音调仍然在播放,尽管延迟时间更长。这种行为是否符合规范?当我离开标签时,requestAnimationFrame不应该完全停止调用我的回调吗?

一般来说背景标签表示内容被隐藏的标签。这并不一定意味着从一个选项卡切换到另一个旧选项卡将成为背景选项卡,这种行为仅适用于同一浏览器窗口中的选项卡。此外,即使没有切换,选项卡也可以变成"背景"选项卡。当"minimizing"浏览器窗口。
确实,requestAnimationFrame()的行为与文档一致,可能会出现混淆,因为文档没有明确指定它将多次成为paused(在随后的恢复中)。
关于规范,没有,就像所有内置到web平台的计时器一样,所以除了每个浏览器实现它自己的特性所指定的行为之外。
requestAnimationFrame()应该停止调用回调完全当移动远离标签?也许吧,但是由于规范和标准都没有记录这种行为,因此没有明确的答案。无论如何,如果这是主要需求,它可以很容易地实现页面可见性API,特别是document.visibilityState,如下:

function playAudio() {
const ctx = new AudioContext();
const osc = ctx.createOscillator();
const startTime = ctx.currentTime;
const stopTime = startTime + 0.2;
osc.frequency.value = 440;
osc.connect(ctx.destination);
osc.start(startTime);
osc.stop(stopTime);
}
let lastActionTime = 0;
function action(timestamp) {
console.log(timestamp);
window.requestAnimationFrame(action);
if (document.visibilityState === 'hidden')
return;
if (timestamp - lastActionTime < 1000) {  // Throttle
return
}
playAudio()
lastActionTime = timestamp
}
function startAction() {
window.requestAnimationFrame(action);
}
window.onload = function() {
const startButton = document.getElementById("start");
startButton.addEventListener("click", startAction)
}
<button id="start">Start</button>

这里发生的事情是,Firefox在具有活动AudioContext时不会限制任何计时器,正如我在https://bugzilla.mozilla.org/show_bug.cgi?id=1344524#c26

中被告知的那样

正在运行的AudioContext将禁用定时器节流

所以你的测试本身就是导致它失败的原因。注册回调在数组中触发的次数,您将看到它确实被节流了。

关于规格,他们确实提供了一些余地,因为这主要是一个性能/节省电池的优化,并不是所有设备都需要相同的。所以关于何时触发动画帧的所有规定都是

如果活动文档被渲染阻塞,则可导航栏没有渲染机会;否则,呈现机会取决于硬件约束(如显示刷新率)和其他因素(如页面性能或文档的可见性状态是否为"可见")。渲染机会通常以一定的间隔出现。

注意:本规范没有强制使用任何特定的模型来选择呈现机会。但是,如果浏览器试图达到60Hz的刷新率,那么渲染机会最多每60秒(约16.7ms)出现一次。如果浏览器发现一个可导航栏无法维持这个速率,它可能会降低到更可持续的每秒30次渲染机会,而不是偶尔丢弃帧。同样,如果可导航页不可见,用户代理可能会决定将该页面降低到每秒4次渲染机会,甚至更少。

(其中"注释"Section不具有权威性)

最新更新