Back

requestAnimationFrame vs setTimeout: Wann welche Methode verwenden

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 Updates
  • setTimeout 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ährend setTimeout 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
}

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

AnwendungsfallBeste WahlGrund
Flüssige AnimationenrequestAnimationFrameSynchronisiert mit Display-Refresh
Canvas/WebGL-RenderingrequestAnimationFrameVerhindert Tearing und Jank
API-PollingsetTimeoutNicht an visuelle Updates gebunden
Benutzereingaben-DebouncingsetTimeoutBenötigt präzise Verzögerungskontrolle
Fortschrittsbalken während AnimationrequestAnimationFrameVisuelles Feedback erforderlich
HintergrunddatenverarbeitungsetTimeoutLäuft weiter bei inaktivem Tab
Game LoopsrequestAnimationFrameOptimale 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.

OpenReplay