Start · Sprachen · JavaScript · Referenz · Window.cancelAnimationFrame()

Window.cancelAnimationFrame()

Methode

Bricht einen zuvor mit <code>requestAnimationFrame()</code> geplanten Callback ab, sodass er vor dem nächsten Neuzeichnen nicht ausgeführt wird.

seit JavaScript Baseline: alle Browser (seit 2015) Kategorie: webapi

Signatur

window.cancelAnimationFrame(requestID)

Beschreibung

window.cancelAnimationFrame() ist das Gegenstück zu window.requestAnimationFrame(). Jeder Aufruf von requestAnimationFrame() gibt eine ganzzahlige ID zurück. Mit dieser ID lässt sich der geplante Callback wieder aus der Warteschlange nehmen, solange er noch nicht ausgeführt wurde.

Gebraucht wird die Methode vor allem, um Animationsschleifen anzuhalten, z. B. wenn der Nutzer auf „Stopp“ klickt, eine Komponente aus dem DOM entfernt wird (Aufräumen in Frameworks wie React, Vue oder Web Components) oder eine neue Animation die alte ersetzen soll. Ohne Abbruch laufen Schleifen weiter, verbrauchen CPU/Akku und greifen womöglich auf DOM-Elemente zu, die es nicht mehr gibt.

Wichtig: Bei einer rekursiven Schleife plant jeder Frame einen neuen Callback mit einer neuen ID. Du musst also immer die zuletzt zurückgegebene ID speichern und abbrechen. Die ID eines Callbacks, der schon gelaufen ist, abzubrechen, bringt nichts.

Parameter

Name Typ Default Beschreibung
$requestID Pflicht number Die ID, die der Aufruf von window.requestAnimationFrame() zurückgegeben hat, der abgebrochen werden soll. Eine ungültige oder schon verbrauchte ID wird still ignoriert.

Rückgabewert

Typ
void
Beschreibung
Gibt undefined zurück.

Beispiele

Einzelnen geplanten Frame abbrechen

const id = requestAnimationFrame(() => {
  console.log('Wird nie ausgegeben');
});

// Noch vor dem nächsten Neuzeichnen abbrechen
cancelAnimationFrame(id);
console.log('Frame abgebrochen, ID:', typeof id);
Frame abgebrochen, ID: number

Animationsschleife mit Start/Stopp-Buttons

const box = document.querySelector('#box');
const startBtn = document.querySelector('#start');
const stopBtn = document.querySelector('#stop');

let rafId = null;
let x = 0;

const step = () => {
  x = (x + 2) % 400;
  box.style.transform = `translateX(${x}px)`;
  // Immer die NEUESTE ID speichern
  rafId = requestAnimationFrame(step);
};

startBtn.addEventListener('click', () => {
  if (rafId === null) rafId = requestAnimationFrame(step);
});

stopBtn.addEventListener('click', () => {
  if (rafId !== null) {
    cancelAnimationFrame(rafId);
    rafId = null;
  }
});

Zeitlich begrenzte Animation mit Abbruchfunktion

const animate = (durationMs, onFrame) => {
  let id;
  const start = performance.now();

  const tick = (now) => {
    const progress = Math.min((now - start) / durationMs, 1);
    onFrame(progress);
    if (progress < 1) id = requestAnimationFrame(tick);
  };

  id = requestAnimationFrame(tick);
  // Rückgabe: Funktion zum Abbrechen
  return () => cancelAnimationFrame(id);
};

const cancel = animate(2000, (p) => {
  document.body.style.opacity = String(1 - p);
});

// Nach 500 ms abbrechen, z. B. weil der Nutzer weiternavigiert
setTimeout(() => {
  cancel();
  console.log('Animation abgebrochen');
}, 500);
Animation abgebrochen

Aufräumen in einer Web Component

class Spinner extends HTMLElement {
  #rafId = 0;
  #angle = 0;

  connectedCallback() {
    const loop = () => {
      this.#angle = (this.#angle + 4) % 360;
      this.style.transform = `rotate(${this.#angle}deg)`;
      this.#rafId = requestAnimationFrame(loop);
    };
    this.#rafId = requestAnimationFrame(loop);
  }

  disconnectedCallback() {
    // Schleife stoppen, wenn das Element entfernt wird
    cancelAnimationFrame(this.#rafId);
  }
}

customElements.define('x-spinner', Spinner);

// Wichtig · Fallstricke

  • Neueste ID speichern: In rekursiven Schleifen ändert sich die ID mit jedem Frame. Wer nur die erste ID speichert, kann die Schleife nicht mehr stoppen.
  • Abbruch innerhalb des Callbacks: Ruft ein laufender Callback cancelAnimationFrame() für seine eigene ID auf, passiert nichts, denn er läuft schon. Um die Schleife zu beenden, plane einfach keinen weiteren Frame (z. B. über ein Flag).
  • Keine Fehler: Ungültige IDs (undefined, 0, verbrauchte IDs) werfen keine Ausnahme. Tippfehler oder falsch gespeicherte IDs bleiben deshalb leicht unbemerkt.
  • Die IDs gehören zum jeweiligen Fenster bzw. Worker. Eine ID aus einem iframe lässt sich nicht im Elternfenster abbrechen.
  • Kompatibilität: Wird von allen modernen Browsern unterstützt, auch in Dedicated Workers (zusammen mit OffscreenCanvas). Präfixe wie webkitCancelAnimationFrame oder mozCancelAnimationFrame braucht man nur noch für sehr alte Browser. In Node.js gibt es die Methode nicht.
  • In Hintergrund-Tabs pausieren Browser die requestAnimationFrame-Callbacks. Ein Abbruch ist dort trotzdem nötig, damit die Schleife nach der Rückkehr zum Tab nicht wieder anläuft.