Start · Sprachen · JavaScript · Referenz · DedicatedWorkerGlobalScope.requestAnimationFrame()

DedicatedWorkerGlobalScope.requestAnimationFrame()

Methode

Plant innerhalb eines Dedicated Workers einen Rückruf, der vor dem nächsten Neuzeichnen ausgeführt wird – ideal für Animationen auf einem <code>OffscreenCanvas</code>.

seit JavaScript Chrome 69+, Firefox 97+, Safari 16.4+ (nur in Dedi Kategorie: webapi

Signatur

DedicatedWorkerGlobalScope.requestAnimationFrame(callback)

Beschreibung

requestAnimationFrame() ist im Kontext eines Dedicated Workers (self in einem mit new Worker() gestarteten Skript) verfügbar und funktioniert wie window.requestAnimationFrame(): Die übergebene Funktion wird genau einmal aufgerufen, bevor der Browser das nächste Bild darstellt. Sie ist also kein Dauer-Timer – wer eine fortlaufende Animation will, muss innerhalb des Rückrufs erneut requestAnimationFrame() aufrufen.

Hauptzweck ist das Rendern auf einem OffscreenCanvas, das per canvas.transferControlToOffscreen() an den Worker übergeben wurde. So laufen aufwendige Zeichen- oder WebGL-Operationen außerhalb des Hauptthreads, ohne dass die Bildrate von blockierendem UI-Code abhängt. Die Bildrate richtet sich nach der Bildwiederholfrequenz des Anzeigegeräts (meist 60 Hz, bei 120-Hz-Displays entsprechend höher).

Der Rückruf erhält einen DOMHighResTimeStamp, der den Zeitpunkt des Frames beschreibt. Diesen sollte man für zeitbasierte Animationen verwenden (Delta-Zeit), statt pro Frame einen festen Schritt anzunehmen. Mit dem zurückgegebenen Handle lässt sich die Anfrage über cancelAnimationFrame() wieder zurückziehen.

Parameter

Name Typ Default Beschreibung
$callback Pflicht (timestamp: DOMHighResTimeStamp) => void Funktion, die vor dem nächsten Neuzeichnen aufgerufen wird. Erhält als einziges Argument einen Zeitstempel in Millisekunden (vergleichbar mit performance.now()).

Rückgabewert

Typ
number
Beschreibung
Eine ganzzahlige, von 0 verschiedene Anfrage-ID (long), die an cancelAnimationFrame() übergeben werden kann, um den Rückruf abzubrechen.

Beispiele

OffscreenCanvas an einen Worker übergeben und animieren

// main.js
const canvas = document.querySelector('#bühne');
const offscreen = canvas.transferControlToOffscreen();
const worker = new Worker('render-worker.js');
worker.postMessage({ canvas: offscreen }, [offscreen]);

// render-worker.js
let ctx;
let x = 0;

const zeichne = (timestamp) => {
  const { width, height } = ctx.canvas;
  ctx.clearRect(0, 0, width, height);
  ctx.fillStyle = 'tomato';
  ctx.fillRect(x, height / 2 - 20, 40, 40);
  x = (x + 2) % width;
  self.requestAnimationFrame(zeichne); // nächsten Frame anfordern
};

self.onmessage = ({ data }) => {
  ctx = data.canvas.getContext('2d');
  self.requestAnimationFrame(zeichne);
};

Zeitbasierte Bewegung mit Delta-Zeit

// render-worker.js
let ctx;
let letzterZeitpunkt = null;
let winkel = 0;
const GRAD_PRO_SEKUNDE = 90;

const frame = (timestamp) => {
  if (letzterZeitpunkt === null) letzterZeitpunkt = timestamp;
  const delta = (timestamp - letzterZeitpunkt) / 1000; // Sekunden
  letzterZeitpunkt = timestamp;

  winkel = (winkel + GRAD_PRO_SEKUNDE * delta) % 360;

  const { width, height } = ctx.canvas;
  ctx.resetTransform();
  ctx.clearRect(0, 0, width, height);
  ctx.translate(width / 2, height / 2);
  ctx.rotate((winkel * Math.PI) / 180);
  ctx.fillRect(-25, -25, 50, 50);

  self.requestAnimationFrame(frame);
};

self.onmessage = ({ data }) => {
  ctx = data.canvas.getContext('2d');
  self.requestAnimationFrame(frame);
};

Animation per Nachricht starten und stoppen

// render-worker.js
let ctx;
let anfrageId = 0;
let farbwert = 0;

const schleife = () => {
  farbwert = (farbwert + 1) % 360;
  ctx.fillStyle = `hsl(${farbwert} 80% 50%)`;
  ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  anfrageId = self.requestAnimationFrame(schleife);
};

self.onmessage = ({ data }) => {
  if (data.canvas) ctx = data.canvas.getContext('2d');

  if (data.befehl === 'start' && !anfrageId) {
    anfrageId = self.requestAnimationFrame(schleife);
  } else if (data.befehl === 'stop') {
    self.cancelAnimationFrame(anfrageId);
    anfrageId = 0;
    console.log('Animation angehalten');
  }
};

// main.js: worker.postMessage({ befehl: 'stop' });
Animation angehalten

// Wichtig · Fallstricke

  • Nur in Dedicated Workers: In SharedWorker und ServiceWorker existiert die Methode nicht. Vor der Nutzung prüfen: if ('requestAnimationFrame' in self) { … }, sonst auf setTimeout(cb, 16) ausweichen.
  • Kompatibilität: Chromium seit Version 69, Firefox seit 97, Safari erst seit 16.4. Ältere Safari-Versionen unterstützen zudem kein OffscreenCanvas-2D-Kontext.
  • Einmaliger Aufruf: Der Rückruf läuft nur einmal – für Schleifen muss er sich selbst erneut registrieren. Mehrfaches Registrieren pro Frame (z. B. in jedem onmessage) führt zu mehreren parallelen Schleifen und doppelter Geschwindigkeit.
  • Drosselung: Ist das zugehörige Dokument ausgeblendet (Hintergrund-Tab), werden Frames pausiert oder stark gedrosselt. Animationslogik sollte daher mit Delta-Zeit statt mit Frame-Zählern rechnen.
  • Lang laufender Code im Rückruf blockiert den Worker-Thread und verursacht Ruckeln – aber nicht mehr den Hauptthread.