requestAnimationFrame vs setTimeout: Wann welche Methode verwenden

Bei der Entwicklung flüssiger Animationen oder der Planung von Aufgaben in JavaScript kann die Wahl zwischen requestAnimationFrame
und setTimeout
die Performance Ihrer Anwendung erheblich beeinflussen. Obwohl beide Methoden die Ausführung von Funktionen planen, dienen sie grundlegend unterschiedlichen Zwecken und arbeiten mit verschiedenen Timing-Mechanismen.
Wichtigste Erkenntnisse
requestAnimationFrame
synchronisiert sich mit der Display-Bildwiederholrate des Browsers für flüssige visuelle UpdatessetTimeout
bietet universelle Zeitsteuerung für nicht-visuelle Aufgaben und Hintergrundoperationen- Die Verwendung der falschen Methode kann Performance-Probleme, Akkuentladung und schlechte Benutzererfahrung verursachen
requestAnimationFrame
pausiert automatisch in inaktiven Tabs, währendsetTimeout
weiterläuft
Die grundlegenden Unterschiede verstehen
setTimeout: Der universelle Timer
setTimeout
führt eine Funktion nach einer festgelegten Verzögerung in Millisekunden aus. Es ist ein einfacher, vorhersagbarer Timer, der unabhängig vom Rendering-Zyklus des Browsers arbeitet.
// Ausführung nach 1 Sekunde
setTimeout(() => {
console.log('Eine Sekunde ist vergangen');
}, 1000);
// Mit Parametern
setTimeout((message) => {
console.log(message);
}, 2000, 'Hallo nach 2 Sekunden');
Das Hauptmerkmal von setTimeout
ist seine task-queue-basierte Ausführung. Wenn die Verzögerung abläuft, reiht sich der Callback in die Task-Queue der JavaScript Event Loop ein und konkurriert mit anderen Aufgaben um Ausführungszeit.
requestAnimationFrame: Der Animations-Spezialist
requestAnimationFrame
(rAF) synchronisiert sich mit dem Repaint-Zyklus des Browsers und läuft typischerweise mit 60 Bildern pro Sekunde auf den meisten Displays. Es ist speziell für visuelle Updates entwickelt.
function animate(timestamp) {
// Animation basierend auf timestamp aktualisieren
const element = document.getElementById('animated-element');
element.style.transform = `translateX(${timestamp / 10}px)`;
// Animation fortsetzen
if (timestamp < 5000) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);
Performance- und Timing-Überlegungen
Integration in die Browser-Rendering-Pipeline
Der grundlegende Vorteil von requestAnimationFrame
liegt in seiner Integration in die Rendering-Pipeline des Browsers. Während setTimeout
immer dann ausgelöst wird, wenn seine Verzögerung abläuft, werden requestAnimationFrame
-Callbacks kurz vor der Layout-Berechnung und dem Zeichnen der Pixel auf den Bildschirm ausgeführt.
Diese Synchronisation eliminiert häufige Animations-Probleme:
- Screen Tearing: Visuelle Artefakte durch Updates während eines Frames
- Jank: Unregelmäßiges Frame-Timing, das zu ruckelnden Bewegungen führt
- Verschwendete Renders: Zeichnen von Frames, die nie angezeigt werden
Ressourcen-Effizienz
requestAnimationFrame
pausiert automatisch, wenn der Browser-Tab inaktiv wird, was CPU-Zyklen und Akkuleistung spart. setTimeout
läuft in Hintergrund-Tabs weiter, obwohl Browser es nach etwa einer Minute auf einmal pro Sekunde drosseln können.
// Akkuschonende Animations-Schleife
function gameLoop(timestamp) {
updatePhysics(timestamp);
renderGraphics();
requestAnimationFrame(gameLoop);
}
// Ineffizienter Ansatz mit setTimeout
function inefficientLoop() {
updatePhysics();
renderGraphics();
setTimeout(inefficientLoop, 16); // Versuch 60fps zu erreichen
}
Discover how at OpenReplay.com.
Praktische Anwendungsfälle
Wann requestAnimationFrame verwenden
Verwenden Sie requestAnimationFrame
für alle visuellen Updates:
- CSS-Property-Animationen
- Canvas-Zeichenoperationen
- WebGL-Rendering
- DOM-Positions-Updates
- Fortschrittsanzeigen während Animationen
// Smooth-Scroll-Implementierung
function smoothScrollTo(targetY, duration) {
const startY = window.scrollY;
const distance = targetY - startY;
const startTime = performance.now();
function scroll(currentTime) {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
// Easing-Funktion für flüssigere Bewegung
const easeInOutQuad = progress * (2 - progress);
window.scrollTo(0, startY + distance * easeInOutQuad);
if (progress < 1) {
requestAnimationFrame(scroll);
}
}
requestAnimationFrame(scroll);
}
Wann setTimeout verwenden
Wählen Sie setTimeout
für nicht-visuelle Aufgaben:
- Verzögerte API-Aufrufe
- Debouncing von Benutzereingaben
- Polling-Operationen
- Geplante Hintergrundaufgaben
- Einmalige Verzögerungen
// Debounced Search
let searchTimeout;
function handleSearchInput(query) {
clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => {
performSearch(query);
}, 300);
}
// Retry-Logik mit exponential backoff
function fetchWithRetry(url, attempts = 3, delay = 1000) {
return fetch(url).catch(error => {
if (attempts > 1) {
return new Promise(resolve => {
setTimeout(() => {
resolve(fetchWithRetry(url, attempts - 1, delay * 2));
}, delay);
});
}
throw error;
});
}
Häufige Fallstricke und Lösungen
Annahmen zur Bildwiederholrate
Gehen Sie niemals von einer festen Bildwiederholrate bei requestAnimationFrame
aus. Verschiedene Displays haben unterschiedliche Bildwiederholraten (60Hz, 120Hz, 144Hz). Verwenden Sie immer den timestamp-Parameter für zeitbasierte Animationen:
let lastTime = 0;
function animate(currentTime) {
const deltaTime = currentTime - lastTime;
lastTime = currentTime;
const element = document.getElementById('moving-element');
const currentLeft = parseFloat(element.style.left) || 0;
// 100 Pixel pro Sekunde unabhängig von der Bildwiederholrate bewegen
const pixelsPerMs = 100 / 1000;
element.style.left = `${currentLeft + pixelsPerMs * deltaTime}px`;
requestAnimationFrame(animate);
}
Memory Leaks
Speichern und löschen Sie immer Animation-Frame-IDs, wenn Komponenten unmounted werden:
let animationId;
function startAnimation() {
function animate() {
// Animations-Logik hier
animationId = requestAnimationFrame(animate);
}
animationId = requestAnimationFrame(animate);
}
function stopAnimation() {
if (animationId) {
cancelAnimationFrame(animationId);
animationId = null;
}
}
// Aufräumen beim Seitenverlassen
window.addEventListener('beforeunload', stopAnimation);
Schneller Entscheidungsleitfaden
Anwendungsfall | Beste Wahl | Grund |
---|---|---|
Flüssige Animationen | requestAnimationFrame | Synchronisiert mit Display-Refresh |
Canvas/WebGL-Rendering | requestAnimationFrame | Verhindert Tearing und Jank |
API-Polling | setTimeout | Nicht an visuelle Updates gebunden |
Benutzereingaben-Debouncing | setTimeout | Benötigt präzise Verzögerungskontrolle |
Fortschrittsbalken während Animation | requestAnimationFrame | Visuelles Feedback erforderlich |
Hintergrunddatenverarbeitung | setTimeout | Läuft weiter bei inaktivem Tab |
Game Loops | requestAnimationFrame | Optimale Performance und Akkuleistung |
Fazit
Die Wahl zwischen requestAnimationFrame
und setTimeout
geht nicht darum, welche Methode “besser” ist – es geht darum, das richtige Werkzeug für die Aufgabe zu verwenden. Für visuelle Updates und Animationen bietet requestAnimationFrame
durch Browser-Synchronisation überlegene Performance. Für allgemeine Timing-Bedürfnisse und Hintergrundaufgaben bietet setTimeout
die benötigte Flexibilität und Vorhersagbarkeit. Das Verständnis dieser Unterschiede stellt sicher, dass Ihre JavaScript-Anwendungen flüssige Benutzererfahrungen liefern und gleichzeitig Systemressourcen effizient verwalten.
Häufig gestellte Fragen
Obwohl Sie setTimeout mit einer 16,67ms-Verzögerung verwenden können, um 60fps zu approximieren, synchronisiert es sich nicht mit dem tatsächlichen Refresh-Zyklus des Browsers. Dies führt zu dropped frames, Jank und verschwendeten CPU-Zyklen. requestAnimationFrame passt sich automatisch an die Bildwiederholrate des Displays an.
Ja, requestAnimationFrame passt sich an die Bildwiederholrate des Monitors an. Auf einem 120Hz-Display wird es etwa 120 Mal pro Sekunde ausgelöst. Verwenden Sie immer den timestamp-Parameter, um Delta-Zeit zu berechnen und konsistente Animationsgeschwindigkeit auf verschiedenen Displays zu gewährleisten.
Wenn Ihr Callback das Frame-Budget überschreitet, überspringt der Browser Frames, um die Responsivität zu erhalten. Dies verursacht sichtbares Stottern. Erwägen Sie eine Optimierung Ihres Codes, die Verwendung von Web Workers für schwere Berechnungen oder eine Reduzierung der Animations-Komplexität.
Gain control over your UX
See how users are using your site as if you were sitting next to them, learn and iterate faster with OpenReplay. — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.