Wie pausieren / ändern Browser Javascript, wenn Tab oder Fenster nicht aktiv sind?

168

Hintergrund: Ich mache einige Benutzeroberflächentests, bei denen festgestellt werden muss, ob die Leute aufpassen oder nicht. Bei dieser Frage geht es jedoch nicht um die API für die Sichtbarkeit von Seiten .

Insbesondere möchte ich wissen, wie mein Javascript-Code beeinflusst wird, wenn die aktuelle Registerkarte in verschiedenen Browsern nicht aktiv ist oder das Browserfenster nicht aktiv ist. Bisher habe ich Folgendes ausgegraben:

Ich habe folgende Fragen:

  • Unterbrechen Desktop-Browser im Gegensatz zu mobilen Browsern jemals die JS-Ausführung, wenn eine Registerkarte nicht aktiv ist? Wann und welche Browser?
  • Welche Browser reduzieren die setIntervalWiederholung? Ist es nur auf ein Limit oder um einen Prozentsatz reduziert? Wenn ich zum Beispiel eine Wiederholung von 10 ms gegenüber einer Wiederholung von 5000 ms habe, wie wird jede davon betroffen sein?
  • Treten diese Änderungen auf, wenn das Fenster unscharf ist und nicht nur die Registerkarte? (Ich stelle mir vor, es wäre schwieriger zu erkennen, da die OS-API erforderlich ist.)
  • Gibt es andere Effekte, die in einem aktiven Tab nicht beobachtet werden würden? Könnten sie Dinge durcheinander bringen, die sonst korrekt ausgeführt würden (dh die oben genannten Jasmin-Tests)?
Andrew Mao
quelle
Wenn sie angehalten werden, erhalten Websites wie Facebook keine Chat-Nachrichten auf Hintergrund-Registerkarten.
Joseph
1
Ja, es gibt keine Pause, aber ich erinnere mich, dass ich gelesen habe, dass die setInterval/ setTimeoutZeiten unter 1000 ms in 1000 ms geändert werden, wenn die Registerkarte / das Fenster verschwommen ist
Ian
19
@ProfPickle Webmaster? "Ja wirklich?" Dies ist eine JS-Programmierfrage.
Andrew Mao
1
@lan setInterval/ setTimeouttimes under 1000ms werden in 1000ms geändert, wenn die Registerkarte / das Fenster unscharf ist. Nicht klar, was Sie zu vermitteln versucht haben
Amol M Kulkarni
4
+1 Gute Frage. Es wäre gut, einen Vergleich des Browserverhaltens nebeneinander zu sehen, da ich glaube, dass das Klemmverhalten, wenn Registerkarten nicht aktiv sind, nicht Teil eines Standards ist.
UpTheCreek

Antworten:

190

Test Eins

Ich habe speziell für diesen Zweck einen Test geschrieben
: Frameratenverteilung: setInterval vs requestAnimationFrame

Hinweis: Dieser Test ist sehr CPU-intensiv. requestAnimationFramewird von IE 9- und Opera 12- nicht unterstützt.

Der Test protokolliert die tatsächliche Zeit, die für ein nimmt setIntervalund requestAnimationFramein verschiedenen Browsern zu laufen, und gibt Ihnen die Ergebnisse in Form einer Verteilung. Sie können die Anzahl der Millisekunden ändern, um setIntervalzu sehen, wie es unter verschiedenen Einstellungen ausgeführt wird. setTimeoutfunktioniert ähnlich wie a setIntervalin Bezug auf Verzögerungen. requestAnimationFrameIm Allgemeinen werden standardmäßig 60 fps verwendet, je nach Browser. Um zu sehen, was passiert, wenn Sie zu einer anderen Registerkarte wechseln oder ein inaktives Fenster haben, öffnen Sie einfach die Seite, wechseln Sie zu einer anderen Registerkarte und warten Sie eine Weile. Die tatsächliche Zeit, die für diese Funktionen benötigt wird, wird weiterhin auf einer inaktiven Registerkarte protokolliert.

Test zwei

Eine andere Möglichkeit, dies zu testen, besteht darin, den Zeitstempel wiederholt mit setIntervalund zu protokollieren requestAnimationFrameund in einer getrennten Konsole anzuzeigen. Sie können sehen, wie oft es aktualisiert wird (oder ob es jemals aktualisiert wird), wenn Sie die Registerkarte oder das Fenster inaktivieren.

Ergebnisse

Chrome
Chrome begrenzt das Mindestintervall setIntervalauf etwa 1000 ms, wenn die Registerkarte inaktiv ist. Wenn das Intervall höher als 1000 ms ist, wird es im angegebenen Intervall ausgeführt. Es spielt keine Rolle, ob das Fenster unscharf ist, das Intervall ist nur begrenzt, wenn Sie zu einer anderen Registerkarte wechseln. requestAnimationFramewird angehalten, wenn die Registerkarte inaktiv ist.

// Provides control over the minimum timer interval for background tabs.
const double kBackgroundTabTimerInterval = 1.0;

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

Firefox
Ähnlich wie Chrome begrenzt Firefox das Mindestintervall setIntervalauf etwa 1000 ms, wenn die Registerkarte (nicht das Fenster) inaktiv ist. Jedoch requestAnimationFrameläuft langsamer exponentiell , wenn die Lasche nicht aktiv ist, wobei jeder Rahmen unter 1 S, 2S, 4S, 8s und so weiter.

// 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 begrenzt nicht die Verzögerung, setIntervalwenn die Registerkarte inaktiv ist, sondern pausiert requestAnimationFramein inaktiven Registerkarten. Es spielt keine Rolle, ob das Fenster unscharf ist oder nicht.

Kante
Ab Kante 14 setIntervalwird in inaktiven Registerkarten eine Obergrenze von 1000 ms festgelegt. requestAnimationFramewird in inaktiven Registerkarten immer angehalten.

Safari
Genau wie Chrome wird Safari setIntervalauf 1000 ms begrenzt, wenn die Registerkarte inaktiv ist. requestAnimationFramewird ebenfalls angehalten.

Opera
Seit der Einführung der Webkit-Engine zeigt Opera dasselbe Verhalten wie Chrome. setIntervalist auf 1000 ms begrenzt und requestAnimationFramewird angehalten, wenn die Registerkarte inaktiv ist.

Zusammenfassung

Wiederholungsintervalle für inaktive Registerkarten:

           setInterval      requestAnimationFrame 
Chrome
9- nicht betroffen nicht unterstützt
10 nicht betroffen pausiert
11+> = 1000ms pausiert

Feuerfuchs
3- nicht betroffen nicht unterstützt
4 nicht betroffen 1s
5+> = 1000ms 2 n s (n = Anzahl der Frames seit Inaktivität)

IE
9- nicht betroffen nicht unterstützt
10+ nicht betroffen pausiert

Kante
13- nicht betroffen pausiert
14+> = 1000ms pausiert

Safari
5- nicht betroffen nicht unterstützt
6 nicht betroffen pausiert
7+> = 1000ms pausiert

Oper
12- nicht betroffen nicht unterstützt
15+> = 1000ms pausiert
Antonius
quelle
Gute Antwort. Gibt es noch andere mögliche bekannte Unterschiede für andere Funktionen als setIntervalund requestAnimationFrame?
Andrew Mao
1
@ AndrewMao Nicht, dass ich es wüsste. Ich bin auf dieses Problem gestoßen, als ich an einer Bibliothek gearbeitet habe, um zuverlässig zu erkennen, ob JS mit setIntervalund wieder aktiviert wurde requestAnimationFrame. Ich weiß, dass setTimeoutsich setIntervalbeide ähnlich verhalten , da beide in Firefox und Chrome das gleiche minimale Hintergrundintervall haben und in anderen Browsern keine offensichtliche Einschränkung besteht.
Antony
2
Der Firefox setInterval-Mindestwert kann anscheinend geändert werden, indem die URL about:configim Browser geöffnet und der dom.min_background_timeout_valueWert auf etwas anderes als 1000 geändert wird .
Jonas Berlin
Kann ich damit alle 5 Sekunden eine Seite neu laden, wenn der Browser minimiert ist? Hier ist meine Frage.
Shaijut
1
Beachten Sie, dass Chrome die Aufrufrate nicht pausiert / verringert, requestAnimationFramewenn der Benutzer einfach die Anwendung wechselt (Alt + Tab außerhalb von Chrome). Solange die Registerkarte in Chrome aktiv ist, ist die "Bildrate" mehr oder weniger konstant.
Marc
11

Was ich beobachtete: auf inaktiv Tabs in Chrome , alle setTimeout(muss für sein setInterval) wartet weniger als 1000 ms auf gerundet sind 1000 ms . Ich denke, längere Timeouts werden nicht geändert.

Scheint das Verhalten seit Chrome 11 und Firefox 5.0 zu sein : https://developer.mozilla.org/en-US/docs/DOM/window.setTimeout#Inactive_tabs

Außerdem glaube ich nicht, dass es sich so verhält, wenn das gesamte Fenster inaktiv ist (aber es scheint ziemlich einfach zu untersuchen).


quelle
1
jQuerys focusund blurEreignisse scheinen sowohl Registerkarten- als auch Fensterschalter zu erkennen, sodass es möglicherweise in beide Richtungen funktionieren könnte. Aber ich frage mich, wie das Fenster erkennt, ob es tatsächlich sichtbar ist oder nicht.
Andrew Mao
2
Tatsächlich hat es keine Verbindung zu jQuery oder Javascript, da es sich um eine interne Browser-Implementierung handelt.
Können Sie dies jetzt Ende 2016 bestätigen?
vsync
0

Eine neuere Antwort, um diese zu ergänzen: Auf Chrome 78.0.3904.108 stelle ich fest, dass all diese Zeitüberschreitungen (nicht nur die unter 1000 ms) etwas länger dauern als erwartet, wenn ich zu einem anderen Tab wechsle und dann zurückkomme. Das Verhalten, das ich sehe, wird korrekter beschrieben als "Alle Zeitüberschreitungen auf inaktiven Registerkarten können um einen zusätzlichen Betrag auf maximal 1000 ms verzögert werden." ::

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>

Gershom
quelle