1. Web Workers Grundlagen — Der Einstieg in Multithreading im Browser
Der Browser ist von Natur aus single-threaded. Jede schwere Berechnung blockiert den Main Thread — das Ergebnis: eingefrorene UIs, hängende Animationen, frustrierte Nutzer. Web Workers lösen dieses Problem, indem sie JavaScript in einem separaten Thread ausführen, der keinen Zugriff auf das DOM hat, aber beliebige Berechnungen durchführen kann.
BASIC Web Worker erstellen und kommunizieren
Ein Worker wird über die Worker()-Konstruktor-Funktion instanziiert. Die Kommunikation zwischen Main Thread und Worker erfolgt ausschließlich über postMessage() und den onmessage-Handler — beide Seiten kommunizieren asynchron, ohne geteilten Speicher (außer SharedArrayBuffer).
// worker.ts — läuft in separatem Thread
// Kein Zugriff auf DOM, window oder document!
self.onmessage = function(event: MessageEvent) {
const { data, taskId } = event.data;
// Schwere Berechnung — blockiert NICHT den Main Thread
const result = heavyComputation(data);
// Ergebnis zurück an Main Thread senden
self.postMessage({ taskId, result, status: 'done' });
};
function heavyComputation(data: number[]): number {
// Beispiel: Primzahl-Sieb für große Zahlen
return data.reduce((sum, n) => sum + n * n, 0);
}
// Fehlerbehandlung im Worker
self.onerror = (err) => {
self.postMessage({ status: 'error', message: err.message });
};
// main.ts — Main Thread
const worker = new Worker(new URL('./worker.ts', import.meta.url), {
type: 'module' // Moderner ES-Module-Worker
});
// Nachricht an Worker senden
worker.postMessage({
taskId: 'calc-001',
data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
});
// Antwort empfangen
worker.onmessage = (event) => {
const { taskId, result, status } = event.data;
if (status === 'done') {
console.log(`Task ${taskId} abgeschlossen: ${result}`);
}
};
worker.onerror = (err) => {
console.error('Worker Fehler:', err.message);
};
// Worker beenden wenn nicht mehr benötigt
function cleanup() {
worker.terminate(); // Sofortiger Abbruch
}
// Worker Pool für bessere Performance
class WorkerPool {
private workers: Worker[] = [];
private queue: Array<{ resolve: Function, reject: Function, data: any }> = [];
constructor(private size: number = navigator.hardwareConcurrency || 4) {
for (let i = 0; i < this.size; i++) {
this.workers.push(new Worker(new URL('./worker.ts', import.meta.url)));
}
}
terminate() {
this.workers.forEach(w => w.terminate());
}
}
Claude Code Tipp: Claude Code erkennt automatisch wenn du einen Worker erstellen willst und schlägt die korrekte Vite/Webpack-Konfiguration vor. Bei ES-Module-Workers mit type: 'module' generiert Claude Code den passenden Build-Config-Snippet mit.
2. SharedArrayBuffer und Atomics — Echter gemeinsamer Speicher
Mit postMessage() werden Daten standardmäßig kopiert (strukturierter Klon-Algorithmus). Für große Datensätze ist das ineffizient. SharedArrayBuffer erlaubt echten gemeinsamen Speicher zwischen Main Thread und Workers — mit Atomics für sichere, race-condition-freie Zugriffe.
Sicherheitshinweis: SharedArrayBuffer erfordert Cross-Origin Isolation. Du musst folgende HTTP-Header setzen: Cross-Origin-Opener-Policy: same-origin und Cross-Origin-Embedder-Policy: require-corp. Ohne diese Header wirft der Browser einen SecurityError.
SHARED SharedArrayBuffer — parallele Datenzugriffe
Statt Daten hin und her zu kopieren, teilen sich Main Thread und Worker denselben Speicherbereich. Ideal für große Bild-Arrays, Simulationsdaten oder Echtzeit-Berechnungen.
// shared-worker.ts — Worker mit SharedArrayBuffer
self.onmessage = (event) => {
const { sharedBuffer, length, workerIndex, totalWorkers } = event.data;
// Direkt auf geteilten Speicher zugreifen
const sharedArray = new Int32Array(sharedBuffer);
// Jeder Worker bearbeitet seinen Teil des Arrays
const chunkSize = Math.ceil(length / totalWorkers);
const start = workerIndex * chunkSize;
const end = Math.min(start + chunkSize, length);
for (let i = start; i < end; i++) {
// Atomics.add: atomare Addition — thread-safe!
Atomics.add(sharedArray, i, 1);
}
// Signalisieren dass dieser Worker fertig ist
self.postMessage({ done: true, workerIndex });
};
// main.ts — SharedArrayBuffer verwenden
const ARRAY_SIZE = 1_000_000;
const NUM_WORKERS = navigator.hardwareConcurrency || 4;
// Geteilten Speicher erstellen
const sharedBuffer = new SharedArrayBuffer(ARRAY_SIZE * Int32Array.BYTES_PER_ELEMENT);
const sharedArray = new Int32Array(sharedBuffer);
// Array initialisieren
sharedArray.fill(0);
// Mutex mit Atomics implementieren
const mutexBuffer = new SharedArrayBuffer(4);
const mutex = new Int32Array(mutexBuffer);
function acquireMutex() {
while (Atomics.compareExchange(mutex, 0, 0, 1) !== 0) {
Atomics.wait(mutex, 0, 1);
}
}
function releaseMutex() {
Atomics.store(mutex, 0, 0);
Atomics.notify(mutex, 0, 1);
}
// Workers starten und SharedArrayBuffer übergeben
const workers = Array.from({ length: NUM_WORKERS }, (_, i) =>
new Worker(new URL('./shared-worker.ts', import.meta.url))
);
const promises = workers.map((worker, i) =>
new Promise((resolve) => {
worker.onmessage = (e) => { if (e.data.done) resolve(e.data); };
worker.postMessage({
sharedBuffer,
length: ARRAY_SIZE,
workerIndex: i,
totalWorkers: NUM_WORKERS
});
})
);
await Promise.all(promises);
console.log('Alle Workers fertig, Array verarbeitet');
Atomics.wait() / notify()
Für synchrone Koordination zwischen Workers. Blockiert den ausführenden Thread bis eine Bedingung erfüllt ist — NUR in Workers erlaubt, nicht im Main Thread!
Atomics.compareExchange()
Atomarer Compare-and-Swap — die Basis für lock-freie Datenstrukturen und Mutexe. Garantiert Atomizität ohne Locks auf OS-Ebene.
3. Comlink — RPC-ähnliche Worker-Kommunikation mit TypeScript
Rohe postMessage()-Kommunikation ist mühsam: manuelle Task-IDs, Callback-Management, kein TypeScript-Support. Comlink von Google löst das Problem elegant — es macht Worker-Funktionen aufrufbar wie normale async-Funktionen, vollständig typsicher.
COMLINK Typisierter Worker als Remote-Objekt
Mit Comlink wird der Worker zu einem Proxy-Objekt. Jeder Funktionsaufruf wird automatisch über postMessage geroutet und als Promise zurückgegeben — kein manuelles Message-Handling mehr.
// pdf-worker.ts — Comlink Worker
import * as Comlink from 'comlink';
export interface PdfOptions {
title: string;
content: string;
pageSize: 'A4' | 'Letter';
includeFooter: boolean;
}
// Worker-Klasse mit öffentlichen Methoden
class PdfWorkerApi {
private isReady = false;
async initialize(): Promise<void> {
// Schwere Bibliotheken lazy laden
const { PDFDocument } = await import('pdf-lib');
this.isReady = true;
console.log('PDF Worker bereit');
}
async generatePdf(options: PdfOptions): Promise<Uint8Array> {
if (!this.isReady) await this.initialize();
const { PDFDocument, StandardFonts, rgb } = await import('pdf-lib');
const doc = await PDFDocument.create();
const page = doc.addPage(options.pageSize === 'A4' ? [595, 842] : [612, 792]);
const font = await doc.embedFont(StandardFonts.Helvetica);
page.drawText(options.title, {
x: 50, y: page.getHeight() - 80,
size: 24, font, color: rgb(0.1, 0.1, 0.4)
});
page.drawText(options.content, {
x: 50, y: page.getHeight() - 140,
size: 12, font, color: rgb(0.2, 0.2, 0.2),
maxWidth: 495, lineHeight: 18
});
return doc.save();
}
async getProgress(): Promise<number> {
return this.isReady ? 100 : 0;
}
}
// Comlink exponiert die Klasse als Remote-Proxy
Comlink.expose(new PdfWorkerApi());
// main.ts — Comlink Worker aufrufen
import * as Comlink from 'comlink';
import type { PdfWorkerApi } from './pdf-worker';
// Worker instanziieren und als typisiertes Remote-Objekt wrappen
const worker = new Worker(new URL('./pdf-worker.ts', import.meta.url), {
type: 'module'
});
const pdfApi = Comlink.wrap<PdfWorkerApi>(worker);
// Aufruf wie normale async-Funktion — kein postMessage, kein onmessage!
async function handleGeneratePdf() {
const button = document.getElementById('generate-btn')!;
button.textContent = 'Generiere PDF...';
button.disabled = true;
try {
// Initialisierung einmalig
await pdfApi.initialize();
// PDF generieren — läuft im Worker, UI bleibt flüssig
const pdfBytes = await pdfApi.generatePdf({
title: 'Monatsbericht Mai 2026',
content: 'Umsatz: €12.450 | Wachstum: +18% YoY...',
pageSize: 'A4',
includeFooter: true
});
// Download anbieten
const blob = new Blob([pdfBytes], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
Object.assign(document.createElement('a'), { href: url, download: 'report.pdf' }).click();
} finally {
button.textContent = 'PDF generieren';
button.disabled = false;
}
}
Comlink + Transferables: Für große Datenmengen wie ArrayBuffer kannst du Comlink mit Transfer-Objekten kombinieren. Statt kopiert werden ArrayBuffer-Ownership übertragen — das spart Speicher und ist schneller bei Bild- oder Audio-Daten.
4. Service Workers — Intelligentes Caching für Offline-fähige Apps
Service Workers sind ein besonderer Worker-Typ: Sie agieren als Netzwerk-Proxy zwischen Browser und Server, können Requests abfangen und Antworten aus dem Cache liefern. Das Ergebnis sind blitzschnelle Ladezeiten und echte Offline-Fähigkeit.
SW Die drei Caching-Strategien im Vergleich
- Cache First: Erst Cache prüfen, dann Netzwerk. Ideal für statische Assets (JS, CSS, Fonts) die sich selten ändern.
- Network First: Erst Netzwerk, Cache als Fallback. Ideal für API-Daten die möglichst aktuell sein sollen.
- Stale-While-Revalidate: Cache sofort liefern, im Hintergrund aktualisieren. Bestes UX-Erlebnis für semi-dynamische Inhalte.
// service-worker.ts — Vollständiger Service Worker mit allen Strategien
const CACHE_VERSION = 'v3.2.1';
const STATIC_CACHE = `static-${CACHE_VERSION}`;
const DYNAMIC_CACHE = `dynamic-${CACHE_VERSION}`;
const STATIC_ASSETS = [
'/', '/index.html', '/assets/css/style.css',
'/assets/js/app.js', '/offline.html'
];
// Install: Statische Assets precachen
self.addEventListener('install', (event: ExtendableEvent) => {
event.waitUntil(
caches.open(STATIC_CACHE)
.then(cache => cache.addAll(STATIC_ASSETS))
.then(() => (self as any).skipWaiting())
);
});
// Activate: Alte Caches aufräumen
self.addEventListener('activate', (event: ExtendableEvent) => {
event.waitUntil(
caches.keys().then(keys =>
Promise.all(
keys
.filter(k => k !== STATIC_CACHE && k !== DYNAMIC_CACHE)
.map(k => caches.delete(k))
)
)
);
});
// Fetch: Routing-Logik je nach Request-Typ
self.addEventListener('fetch', (event: FetchEvent) => {
const { request } = event;
const url = new URL(request.url);
// API-Requests: Network First
if (url.pathname.startsWith('/api/')) {
event.respondWith(networkFirst(request));
return;
}
// Statische Assets: Cache First
if (STATIC_ASSETS.includes(url.pathname)) {
event.respondWith(cacheFirst(request));
return;
}
// Alles andere: Stale-While-Revalidate
event.respondWith(staleWhileRevalidate(request));
});
// Cache First Strategie
async function cacheFirst(request: Request): Promise<Response> {
const cached = await caches.match(request);
if (cached) return cached;
const response = await fetch(request);
const cache = await caches.open(STATIC_CACHE);
cache.put(request, response.clone());
return response;
}
// Network First Strategie
async function networkFirst(request: Request): Promise<Response> {
try {
const response = await fetch(request);
const cache = await caches.open(DYNAMIC_CACHE);
cache.put(request, response.clone());
return response;
} catch {
return caches.match(request) || new Response('{"error":"offline"}', {
headers: { 'Content-Type': 'application/json' }
});
}
}
// Stale-While-Revalidate Strategie
async function staleWhileRevalidate(request: Request): Promise<Response> {
const cached = await caches.match(request);
// Immer im Hintergrund aktualisieren
const fetchPromise = fetch(request).then(async (response) => {
const cache = await caches.open(DYNAMIC_CACHE);
cache.put(request, response.clone());
return response;
});
return cached || fetchPromise;
}
// app.ts — Service Worker registrieren
async function registerServiceWorker() {
if (!('serviceWorker' in navigator)) {
console.warn('Service Workers nicht unterstützt');
return;
}
try {
const registration = await navigator.serviceWorker.register('/sw.js', {
scope: '/',
updateViaCache: 'none' // Immer nach Updates suchen
});
// Update-Handling für Zero-Downtime-Deploys
registration.addEventListener('updatefound', () => {
const newWorker = registration.installing!;
newWorker.addEventListener('statechange', () => {
if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
showUpdateNotification();
}
});
});
console.log('Service Worker registriert', registration.scope);
} catch (err) {
console.error('Service Worker Fehler:', err);
}
}
registerServiceWorker();
5. Worker Threads in Node.js — Echter Parallelismus auf dem Server
Node.js ist traditionell single-threaded mit Event Loop. Das worker_threads-Modul bringt echten Parallelismus auf den Server — ideal für CPU-intensive Aufgaben wie Bildresizing, Kryptographie oder Datenkompression, ohne den Event Loop zu blockieren.
NODE.JS Worker Threads mit SharedArrayBuffer
In Node.js kommunizieren Worker Threads über parentPort (äquivalent zu postMessage im Browser). SharedArrayBuffer funktioniert genauso wie im Browser — ohne Cross-Origin-Header-Anforderungen.
// image-processor-worker.ts — Node.js Worker Thread
import { workerData, parentPort, isMainThread } from 'worker_threads';
import sharp from 'sharp';
if (isMainThread) {
throw new Error('Dieses Script nur als Worker ausführen!');
}
interface WorkerInput {
imagePath: string;
targetWidth: number;
targetHeight: number;
quality: number;
outputFormat: 'jpeg' | 'png' | 'webp';
}
async function processImage(input: WorkerInput): Promise<void> {
const { imagePath, targetWidth, targetHeight, quality, outputFormat } = input;
try {
// Sharp ist CPU-intensiv — perfekt für Worker Thread
const outputBuffer = await sharp(imagePath)
.resize(targetWidth, targetHeight, { fit: 'cover', position: 'center' })
.toFormat(outputFormat, { quality })
.toBuffer();
parentPort!.postMessage({
status: 'success',
buffer: outputBuffer,
size: outputBuffer.length,
format: outputFormat
}, [outputBuffer.buffer]); // Transfer — kein Kopieren!
} catch (error) {
parentPort!.postMessage({
status: 'error',
message: (error as Error).message
});
}
}
processImage(workerData as WorkerInput);
// image-service.ts — Worker Thread orchestrieren
import { Worker, isMainThread } from 'worker_threads';
import path from 'path';
import os from 'os';
interface ResizeJob {
imagePath: string;
targetWidth: number;
targetHeight: number;
quality?: number;
outputFormat?: 'jpeg' | 'png' | 'webp';
}
// Worker Thread spawnen und auf Ergebnis warten
function resizeImage(job: ResizeJob): Promise<Buffer> {
return new Promise((resolve, reject) => {
const worker = new Worker(
path.join(__dirname, 'image-processor-worker.js'),
{ workerData: { quality: 85, outputFormat: 'webp', ...job } }
);
worker.on('message', (result) => {
if (result.status === 'success') {
resolve(Buffer.from(result.buffer));
} else {
reject(new Error(result.message));
}
worker.terminate();
});
worker.on('error', reject);
});
}
// Parallele Bildverarbeitung mit Worker Pool
async function processImageBatch(jobs: ResizeJob[]): Promise<Buffer[]> {
const maxConcurrent = os.cpus().length;
const results: Buffer[] = [];
// Chunks verarbeiten (respektiert CPU-Anzahl)
for (let i = 0; i < jobs.length; i += maxConcurrent) {
const chunk = jobs.slice(i, i + maxConcurrent);
const chunkResults = await Promise.all(chunk.map(resizeImage));
results.push(...chunkResults);
}
return results;
}
// Express-Route: 10 Bilder parallel → alle unter 2s
export async function handleBatchResize(req: any, res: any) {
const start = Date.now();
const buffers = await processImageBatch(req.body.images);
res.json({ processed: buffers.length, durationMs: Date.now() - start });
}
6. Praxisbeispiele — WASM, Bildverarbeitung und PDF ohne UI-Freeze
Theorie ist gut, Praxis ist besser. Hier sind drei reale Anwendungsfälle die zeigen, wie Claude Code dir hilft, rechenintensive Aufgaben sauber in Workers auszulagern — mit messbaren Performance-Gewinnen.
WASM WebAssembly in einem Web Worker ausführen
WASM-Module können direkt in Workers instanziiert werden. Da WASM-Code oft CPU-intensiv ist (z.B. Bild-Codec, Kryptographie, Physik-Engine), gehört er immer in einen Worker — niemals den Main Thread blockieren!
// wasm-worker.ts — WASM-Modul in Worker laden und nutzen
let wasmInstance: WebAssembly.Instance | null = null;
async function initWasm(): Promise<void> {
// WASM-Binary laden
const response = await fetch('/assets/wasm/image-codec.wasm');
const bytes = await response.arrayBuffer();
// WASM kompilieren und instanziieren (im Worker!)
const { instance } = await WebAssembly.instantiate(bytes, {
env: {
memory: new WebAssembly.Memory({ initial: 256, maximum: 512, shared: true }),
abort: () => throw new Error('WASM abort'),
log: (ptr: number) => console.log('WASM:', ptr)
}
});
wasmInstance = instance;
console.log('WASM Exports:', Object.keys(instance.exports));
}
self.onmessage = async (event) => {
const { type, payload } = event.data;
switch (type) {
case 'init':
await initWasm();
self.postMessage({ type: 'ready' });
break;
case 'encode-webp': {
if (!wasmInstance) throw new Error('WASM nicht initialisiert');
const { imageData, width, height, quality } = payload;
// WASM-Funktion direkt aufrufen
const { encode_webp, alloc, dealloc } = wasmInstance.exports as any;
// Speicher in WASM allozieren
const inputPtr = alloc(imageData.byteLength);
const memory = wasmInstance.exports.memory as WebAssembly.Memory;
new Uint8Array(memory.buffer).set(new Uint8Array(imageData), inputPtr);
// Kodieren
const outputPtr = encode_webp(inputPtr, width, height, quality);
const outputSize = new Int32Array(memory.buffer)[outputPtr / 4];
const outputData = memory.buffer.slice(outputPtr + 4, outputPtr + 4 + outputSize);
dealloc(inputPtr);
dealloc(outputPtr);
self.postMessage({ type: 'encoded', buffer: outputData }, [outputData]);
break;
}
}
};
PRAXIS Canvas-Bildverarbeitung ohne UI-Freeze
OffscreenCanvas ermöglicht Canvas-Rendering direkt im Worker — ohne den Main Thread zu berühren. Ideal für Filter, Effekte oder Echtzeit-Bildbearbeitung.
// canvas-worker.ts — OffscreenCanvas im Worker
self.onmessage = (event) => {
const { canvas, imageData, filter } = event.data;
// OffscreenCanvas direkt im Worker nutzen
const ctx = canvas.getContext('2d')!;
const { width, height } = canvas;
ctx.putImageData(new ImageData(
new Uint8ClampedArray(imageData),
width, height
), 0, 0);
// Filter anwenden
switch (filter) {
case 'grayscale':
applyGrayscale(ctx, width, height);
break;
case 'blur':
applyGaussianBlur(ctx, width, height, 3);
break;
case 'sharpen':
applySharpen(ctx, width, height);
break;
}
self.postMessage({ done: true });
};
function applyGrayscale(ctx: OffscreenCanvasRenderingContext2D, w: number, h: number) {
const imageData = ctx.getImageData(0, 0, w, h);
const { data } = imageData;
for (let i = 0; i < data.length; i += 4) {
// Luminance-Formel (ITU-R BT.709)
const luma = data[i] * 0.2126 + data[i + 1] * 0.7152 + data[i + 2] * 0.0722;
data[i] = data[i + 1] = data[i + 2] = luma;
}
ctx.putImageData(imageData, 0, 0);
}
function applyGaussianBlur(
ctx: OffscreenCanvasRenderingContext2D, w: number, h: number, radius: number
) {
// Box-Blur als schnelle Approximation
const src = ctx.getImageData(0, 0, w, h);
const dst = ctx.createImageData(w, h);
const kernelSize = radius * 2 + 1;
for (let y = 0; y < h; y++) {
for (let x = 0; x < w; x++) {
let r = 0, g = 0, b = 0, count = 0;
for (let ky = -radius; ky <= radius; ky++) {
for (let kx = -radius; kx <= radius; kx++) {
const px = Math.max(0, Math.min(w - 1, x + kx));
const py = Math.max(0, Math.min(h - 1, y + ky));
const idx = (py * w + px) * 4;
r += src.data[idx]; g += src.data[idx + 1]; b += src.data[idx + 2];
count++;
}
}
const outIdx = (y * w + x) * 4;
dst.data[outIdx] = r / count;
dst.data[outIdx + 1] = g / count;
dst.data[outIdx + 2] = b / count;
dst.data[outIdx + 3] = 255;
}
}
ctx.putImageData(dst, 0, 0);
}
// main.ts — OffscreenCanvas an Worker übertragen
const canvas = document.getElementById('preview-canvas') as HTMLCanvasElement;
async function applyFilterInWorker(imageSrc: string, filterName: string) {
// Bild laden und in ImageData konvertieren
const img = await loadImage(imageSrc);
const tmpCanvas = document.createElement('canvas');
tmpCanvas.width = img.width;
tmpCanvas.height = img.height;
const tmpCtx = tmpCanvas.getContext('2d')!;
tmpCtx.drawImage(img, 0, 0);
const imageData = tmpCtx.getImageData(0, 0, img.width, img.height);
// OffscreenCanvas erstellen und an Worker übertragen
const offscreen = canvas.transferControlToOffscreen();
offscreen.width = img.width;
offscreen.height = img.height;
const worker = new Worker(new URL('./canvas-worker.ts', import.meta.url));
return new Promise(resolve => {
worker.onmessage = (e) => {
if (e.data.done) { resolve(true); worker.terminate(); }
};
// Canvas + ImageData transferieren (keine Kopie!)
worker.postMessage(
{ canvas: offscreen, imageData: imageData.data.buffer, filter: filterName,
width: img.width, height: img.height },
[offscreen, imageData.data.buffer]
);
});
}
Performance-Tipp: Nutze navigator.hardwareConcurrency um die optimale Worker-Anzahl zu ermitteln. Auf modernen Rechnern sind 8-16 Cores normal. Claude Code kann dir automatisch einen adaptiven Worker Pool generieren der sich an die verfügbaren CPUs anpasst.
Wichtig — transferControlToOffscreen: Sobald ein Canvas an einen Worker übertragen wurde (transferControlToOffscreen()), kann der Main Thread nicht mehr direkt darauf zeichnen. Das Canvas ist dann exklusiv im Besitz des Workers. Plane die Architektur entsprechend.
7. Claude Code und Web Workers — Der Workflow in der Praxis
Claude Code versteht den vollständigen Worker-Lifecycle. Du beschreibst das Problem — "meine PDF-Generierung friert die UI ein" — und Claude Code analysiert den Code, schlägt die Worker-Architektur vor, generiert Worker-Datei und Main-Thread-Integration inklusive TypeScript-Typen und Fehlerbehandlung.
CLAUDE Was Claude Code für Workers kann
Claude Code kennt nicht nur die APIs — es versteht die Fallstricke: fehlende COOP/COEP-Header für SharedArrayBuffer, transferable vs. clonable Objekte, OffscreenCanvas-Limitations in Safari, und die korrekte Vite/Webpack-Konfiguration für Module-Workers.
- Worker-Architektur analysieren und auf deinen Anwendungsfall anpassen
- Comlink-Integration mit vollständigen TypeScript-Typen generieren
- Service Worker Caching-Strategien je nach Route konfigurieren
- Node.js Worker Thread Pool mit adaptiver Skalierung implementieren
- SharedArrayBuffer-Konfiguration inkl. HTTP-Header für Nginx/Apache
- WASM-Module in Worker-Kontext laden und Speicher-Management
- Performance-Benchmarks vor/nach Worker-Migration erstellen
Beispiel-Prompt für Claude Code: "Ich habe eine React-App die beim Filtern von 50.000 Datensätzen die UI einfriert. Extrahiere die Filter-Logik in einen Web Worker mit Comlink, TypeScript-Typen und einem WorkerPool der navigator.hardwareConcurrency nutzt."
Performance-Modul im Kurs
Im Claude Code Mastery Kurs: Web Workers, WASM, Service Worker Caching und Node.js Worker Threads — vollständige Parallelisierungs-Strategien für Browser und Server.
14 Tage kostenlos testen →