Warum Browser JavaScript-Timer drosseln
(nolanlawson.com)- In JavaScript wird
setTimeout(0)in der Praxis oft nicht sofort ausgeführt, sondern mit einer Mindestverzögerung von 4 ms, was eine grundlegende Browser-Beschränkung zur Verhinderung von Missbrauch ist - Solche Einschränkungen sollen verhindern, dass Websites Timer wahllos missbrauchen und dadurch Akkuverbrauch oder schlechtere Interaktionen verursachen; im Akkubetrieb kann die Grenze auf 16 ms steigen, in Hintergrund-Tabs sogar auf 1 Sekunde
- Entwickler haben verschiedene alternative Timer-APIs genutzt, um die Grenzen von
setTimeoutzu umgehen, daruntersetImmediate,MessageChannel.postMessage,window.postMessageundscheduler.postTask - Reale Benchmark-Ergebnisse zeigen, dass in Chrome und Firefox das 4-ms-Clamping greift, während
MessageChannelundscheduler.postTasknahezu ohne Verzögerung arbeiten; Safari drosseltsetTimeoutnoch stärker - Im Kern geht es um das Gleichgewicht zwischen dem Schutz der Nutzererfahrung und der Freiheit von Entwicklern; derzeit etabliert sich die Scheduler API als standardisierte Lösung, doch bei Missbrauch könnte eine neue Browser-Intervention eingeführt werden
Hintergrund der setTimeout-Beschränkung
- Selbst bei
setTimeout(0)erfolgt die tatsächliche Ausführung wegen Missbrauchs oft erst nach mindestens 4 msconst start = performance.now() setTimeout(() => { // wird nach etwa 4 ms ausgeführt console.log(performance.now() - start) }, 0) - Damit sollen wahllose wiederholte Aufrufe verhindert und Akkuverbrauch sowie Render-Verzögerungen reduziert werden
- Einige Browser verschärfen die Begrenzung je nach Umgebung
- Akkubetrieb: im alten Edge 16 ms
- Hintergrund-Tab: in Chrome Verzögerung von bis zu 1 Sekunde
Entstehung anderer Timer-APIs
setImmediate: nur in IE und altem Edge unterstützt, faktisch eingestelltMessageChannel.postMessage: überträgt Aufgaben über einen separaten Kanal an den Event Loopwindow.postMessage: gute Performance, aber Risiko von Kollisionen mit anderen Skriptenscheduler.postTask: in modernen Browsern unterstützt und als stabilste Option bewertet
Benchmark-Ergebnisse (MacBook Pro 2021, 101 Wiederholungen)
- Chrome 139:
setTimeout4.2 ms,scheduler.postTask0 ms - Firefox 142:
setTimeout4.72 ms,scheduler.postTask0.01 ms - Safari 18.4:
setTimeout26.73 ms,MessageChannel0.52 ms,window.postMessage0.05 ms
Fallbeispiel fake-indexeddb
- IndexedDB möchte Transaktionen direkt nach dem Ende der Mikrotasks des Event Loops automatisch committen
setImmediatein Node.js ist dafür ideal, aber im Browser istsetTimeoutineffizient- Ein Vorgang, der in Chrome 300 ms dauert, dehnt sich im Browser auf bis zu 4,8 Sekunden aus
- Als Lösung wird standardmäßig
scheduler.postTaskverwendet und aus KompatibilitätsgründenMessageChannel/window.postMessageals Fallback übernommen
Debatte um Browser-Interventionen
- Eine Seite argumentiert, Timer müssten begrenzt werden, damit Entwickler vor sich selbst geschützt werden
- Die andere Seite fordert, Freiheit zu gewährleisten, damit Entwickler selbst messen und optimieren können
- Letztlich greifen Browser nach dem Prinzip „Nutzer zuerst“ ein, um Missbrauch zu verhindern
- Die Scheduler API versucht beide Positionen zu vereinen, indem sie Entwicklern eine feinere Kontrolle über Aufgaben gibt und zugleich auf die Rendering-Pipeline des Browsers abgestimmt ist
Ausblick
postTaskundpostMessagewerden vermutlich vorerst ohne Drosselung bestehen bleiben- Werden jedoch hohe Prioritäten wie
user-blockingmissbraucht, sind erneute Eingriffe möglich - Langfristig könnte eine weitere alternative API wie
scheduler2nötig werden
Noch keine Kommentare.