Start · Sprachen · JavaScript · Referenz · Worklet

Worklet

Schnittstelle

Das Interface <code>Worklet</code> ist eine schlanke Variante von Web Workers, mit der Skriptcode direkt in niedrigen Stufen der Rendering- oder Audio-Pipeline läuft.

seit JavaScript Baseline (AudioWorklet): alle modernen Browser; Pa Kategorie: webapi

Signatur

interface Worklet

Beschreibung

Worklet ist die abstrakte Basisschnittstelle für kleine, stark eingeschränkte Skriptumgebungen. Sie laufen unabhängig vom Haupt-Thread und hängen sich in eine bestimmte Stufe der Browser-Pipeline ein, etwa die Audioverarbeitung oder das Zeichnen. Anders als ein Worker erzeugt man ein Worklet nicht selbst mit new. Der Browser stellt feste Instanzen bereit, zum Beispiel audioContext.audioWorklet oder CSS.paintWorklet.

Die Schnittstelle hat genau eine Methode: addModule(moduleURL, options). Sie lädt ein ES-Modul in den globalen Bereich des Worklets (WorkletGlobalScope) und gibt ein Promise zurück. Das Promise wird erfüllt, sobald das Modul geladen und ausgeführt ist. Im Modul registriert man dann Klassen, zum Beispiel mit registerProcessor() (Audio) oder registerPaint() (CSS Painting API).

Die wichtigsten Unterklassen bzw. Einsatzgebiete:

  • AudioWorklet: eigene Audioverarbeitung mit geringer Latenz im Audio-Rendering-Thread. Diese Variante wird von allen Browsern unterstützt.
  • PaintWorklet (CSS.paintWorklet): eigene Hintergründe und Rahmen über paint() in CSS.
  • AnimationWorklet und LayoutWorklet: experimentelle Houdini-APIs.

Worklet-Code ist bewusst zustandsarm gehalten. Der Browser darf mehrere globale Bereiche parallel erzeugen oder wieder verwerfen. DOM-Zugriff, fetch und setTimeout gibt es dort in der Regel nicht.

Parameter

Name Typ Default Beschreibung
$moduleURL Pflicht string | URL Parameter von addModule(): URL des JavaScript-Moduls, das in den WorkletGlobalScope geladen wird. Relative Pfade werden relativ zum Dokument aufgelöst. Blob-URLs sind erlaubt.
$options { credentials?: 'omit' | 'same-origin' | 'include' } { credentials: 'same-origin' } Parameter von addModule(): legt fest, ob beim Laden des Moduls Anmeldedaten (Cookies, HTTP-Authentifizierung) mitgeschickt werden.

Rückgabewert

Typ
Promise<undefined>
Beschreibung
addModule() gibt ein Promise zurück. Es wird erfüllt, wenn das Modul geladen und ausgewertet ist. Bei einem Netzwerk- oder Syntaxfehler wird es mit einem Fehler abgelehnt (in der Regel AbortError bzw. SyntaxError).

Beispiele

AudioWorklet: eigenen Gain-Prozessor laden

// gain-processor.js (läuft im AudioWorkletGlobalScope)
// class GainProcessor extends AudioWorkletProcessor {
//   process(inputs, outputs) {
//     const input = inputs[0], output = outputs[0];
//     for (let ch = 0; ch < input.length; ch++) {
//       for (let i = 0; i < input[ch].length; i++) {
//         output[ch][i] = input[ch][i] * 0.5;
//       }
//     }
//     return true; // Prozessor aktiv halten
//   }
// }
// registerProcessor('gain-processor', GainProcessor);

// main.js
const startAudio = async () => {
  const ctx = new AudioContext();
  // ctx.audioWorklet ist eine Worklet-Instanz
  await ctx.audioWorklet.addModule('gain-processor.js');
  const osc = new OscillatorNode(ctx, { frequency: 440 });
  const gain = new AudioWorkletNode(ctx, 'gain-processor');
  osc.connect(gain).connect(ctx.destination);
  osc.start();
  console.log('Worklet geladen:', ctx.audioWorklet instanceof Worklet);
};

document.querySelector('#play').addEventListener('click', startAudio);
Worklet geladen: true

PaintWorklet: Schachbrett-Hintergrund per CSS

// checkerboard.js (läuft im PaintWorkletGlobalScope)
// registerPaint('checkerboard', class {
//   paint(ctx, size) {
//     const s = 16;
//     for (let y = 0; y < size.height / s; y++) {
//       for (let x = 0; x < size.width / s; x++) {
//         ctx.fillStyle = (x + y) % 2 ? '#ddd' : '#fff';
//         ctx.fillRect(x * s, y * s, s, s);
//       }
//     }
//   }
// });

// main.js — Feature-Erkennung, weil nicht alle Browser das unterstützen
if ('paintWorklet' in CSS) {
  await CSS.paintWorklet.addModule('checkerboard.js');
  document.body.style.backgroundImage = 'paint(checkerboard)';
} else {
  console.warn('CSS Painting API nicht verfügbar');
}

Modul aus Blob-URL laden und Fehler behandeln

const code = `
  registerProcessor('silence', class extends AudioWorkletProcessor {
    process() { return false; }
  });
`;
const url = URL.createObjectURL(new Blob([code], { type: 'text/javascript' }));

const ctx = new AudioContext();
try {
  await ctx.audioWorklet.addModule(url, { credentials: 'omit' });
  console.log('Modul registriert');
} catch (err) {
  console.error('Laden fehlgeschlagen:', err.name);
} finally {
  URL.revokeObjectURL(url);
}
Modul registriert

// Wichtig · Fallstricke

  • Kein Konstruktor: new Worklet() wirft einen TypeError. Man verwendet immer eine vom Browser bereitgestellte Instanz wie audioContext.audioWorklet oder CSS.paintWorklet.
  • Sicherer Kontext: addModule() funktioniert nur über HTTPS oder localhost. Über file:// scheitert das Laden.
  • CORS/CSP: Module von fremden Ursprüngen brauchen passende CORS-Header. Die CSP-Direktive script-src gilt auch für Worklet-Module, bei Blob-URLs muss blob: erlaubt sein.
  • Keine Zustandsgarantie: Der Browser kann mehrere globale Bereiche erzeugen und wieder verwerfen. Globale Variablen im Worklet sind daher kein verlässlicher Speicher.
  • Kompatibilität: AudioWorklet läuft in allen aktuellen Browsern. CSS.paintWorklet gibt es in Chromium-Browsern, in Firefox und Safari fehlt es oder ist nur eingeschränkt vorhanden. AnimationWorklet und LayoutWorklet sind experimentell. Deshalb immer per Feature-Erkennung prüfen.
  • Mehrfaches addModule() mit derselben URL lädt das Modul nicht erneut. Ein zweites registerProcessor() mit gleichem Namen wirft dagegen einen NotSupportedError.