Web Workers — Parallel JavaScript uden main thread-blokning
Web Workers kører JavaScript i en baggrundstråd. Main thread forbliver fri til brugerinteraktion — INP forbedres. Workers kan ikke tilgå DOM men kommunikerer via postMessage.
JavaScript er single-threaded: al eksekvering foregår på main thread, og lange JavaScript-operationer blokerer UI-opdateringer og brugerinteraktion direkte. Web Workers løser dette ved at flytte CPU-intensiv beregning til en separat baggrundstråd, så main thread forbliver responsiv. For SEO og Core Web Vitals er Workers relevante fordi de reducerer long tasks og forbedrer INP (Interaction to Next Paint) — den Core Web Vitals-metric der måler responsivitet ved brugerinteraktion og er en direkte Google rankingfaktor.
Hvornår Web Workers er løsningen
Workers hjælper når du har CPU-intensive opgaver der tager over 50ms og ikke er afhængige af DOM:
- Parsning af store JSON-datasæt
- Kryptografiske operationer
- Billedbehandling (pixelmanipulation via canvas)
- Søgeindeksering (Pagefind kører bl.a. sin søgemaskine i Workers)
- Dataanalyse og aggregering
- Komprimering/dekomprimering
Workers hjælper ikke for operationer der kræver DOM-adgang (brug requestAnimationFrame i stedet) eller for I/O-bound operationer der allerede er asynkrone.
Grundlæggende Worker API
Opret en Worker:
// main.js
const worker = new Worker('/worker.js');
worker.postMessage({ data: largeDataset, operation: 'process' });
worker.onmessage = (event) => {
const result = event.data;
updateUI(result); // DOM-opdatering sker stadig på main thread
};
worker.onerror = (error) => console.error(error);
// worker.js
self.onmessage = (event) => {
const { data, operation } = event.data;
// Tung beregning — blokerer ikke main thread
const result = processData(data);
self.postMessage(result);
};
Transferable Objects — undgå datakopi-overhead
postMessage kopierer data som standard (structured clone). For store datasets er dette dyrt. Transferable Objects overfører ownership af data uden kopi — zero-copy transfer:
const buffer = new ArrayBuffer(1024 * 1024 * 10); // 10 MB
// Kopierer data — langsomt for store buffere
worker.postMessage(buffer);
// Overfører ownership — øjeblikkeligt, buffer er nu tom i main thread
worker.postMessage(buffer, [buffer]);
ArrayBuffer, MessagePort og OffscreenCanvas er transferable.
SharedArrayBuffer — delt hukommelse
SharedArrayBuffer deler hukommelse mellem main thread og Workers uden kopi. Kræver COOP/COEP headers (Cross-Origin Isolation):
const sharedBuffer = new SharedArrayBuffer(1024);
const sharedArray = new Int32Array(sharedBuffer);
worker.postMessage({ buffer: sharedBuffer });
// Begge threads læser/skriver til samme hukommelse
// Brug Atomics for thread-safe operationer
Worker Pools
For gentagne opgaver er det ineffektivt at oprette og terminere Workers per opgave. En Worker Pool genanvender Workers:
class WorkerPool {
constructor(url, size = navigator.hardwareConcurrency || 4) {
this.workers = Array.from({ length: size }, () => new Worker(url));
this.queue = [];
this.available = [...this.workers];
}
run(data) {
return new Promise((resolve) => {
const execute = () => {
const worker = this.available.pop();
worker.onmessage = (e) => {
this.available.push(worker);
resolve(e.data);
if (this.queue.length) this.queue.shift()();
};
worker.postMessage(data);
};
this.available.length ? execute() : this.queue.push(execute);
});
}
}
INP-effekten
En 200ms JSON-parsing operation på main thread resulterer i 200ms long task og dårlig INP. Flytning til Worker reducerer main thread-bidrag til postMessage-kald (< 1ms) og onmessage-callback (< 1ms). Brugerinteraktion forbliver responsiv under hele operationen.
Biblioteker som Comlink (Google) abstraherer Worker-kommunikation til normale async funktionskald og eliminerer manuel postMessage-håndtering.
→ Denne artikel er en del af Web Performance — Core Web Vitals og teknisk hastighed.
Andre artikler i samme emne
- Animation performance — Frame rate og jank-fri bevægelse
- Billedoptimering — Formater, størrelser og SEO
- Browser rendering pipeline — Fra HTML til pixels
- CLS-problemer — Årsager til Cumulative Layout Shift og løsninger
- Core Web Vitals — LCP, INP og CLS forklaret
- CSS — Cascading Style Sheets og SEO
- CSS containment — Isolér rendering og accelerér layout
- Font-optimering — Webfonts, FOUT og SEO
- HTTP/2 og HTTP/3 — Protokoller der eliminerer latency-overhead
- INP-optimering — Interaction to Next Paint og Core Web Vitals
- JavaScript bundle-optimering — Code splitting, tree shaking og analyse
- Kritisk renderingsti — Hvad browseren gør før du ser noget
- Latency — Forsinkelse i netværket og hvad du kan gøre ved det
- Lazy loading — Udskyd indlæsning af billeder og ressourcer
- LCP-optimering — Sådan forbedrer du Largest Contentful Paint
- Long Tasks og LoAF — Hvad blokerer main thread
- Navigation og resource timings — Browserens performance-API
- PageSpeed og SEO — Hastighed som rankingfaktor
- Performance budgets — Grænser der forhindrer regressioner
- Performance timings — Hvornår er det for langsomt?
- Resource hints — Preload, prefetch og preconnect til SEO
- Responsive images — srcset, sizes og art direction
- Responsivt design — Mobile-first og SEO
- RUM vs. syntetisk monitoring — To syn på web performance
- Service Workers — Offline caching og PWA performance
- Speculative loading — Prefetch og prerender af næste side
- Startup performance — Hurtig app-start og time to interactive
- Tredjeparts-scripts og performance — Impact og strategier
- Tredjepartsscripts — Analytics, ads og performance-konsekvenser
- TTFB og hosting — Server response time og SEO
- Video performance — Lazy loading, formater og indlæsningsstrategi
- Viewport tag — Meta viewport og mobil-rendering
Ofte stillede spørgsmål
- Hvad kan Web Workers ikke gøre?
- Web Workers har ingen adgang til DOM, window, document eller lokationsbaserede browser-APIs. De kan ikke direkte manipulere siden. Al kommunikation foregår via postMessage og strukturerede data-kopi (eller SharedArrayBuffer for shared memory). Workers egner sig til beregning, databehandling og netværkskald — ikke til UI-opdateringer.
- Hvad er forskellen på Web Workers, Service Workers og Worklets?
- Web Workers er generelle baggrundstråde til vilkårlig JavaScript-beregning. Service Workers er en specialiseret Worker der intercepter netværkskald og muliggør offline caching og push notifications. Worklets (Audio Worklet, Paint Worklet, Animation Worklet) er letvægtsudvidelser til browser-rendering pipelines med meget begrænset API-adgang.
- Hvornår er Web Workers den rigtige løsning frem for async/await?
- Async/await og Promises løser I/O-bound asynkronitet: netværkskald, fil-læsning og timeouts. Web Workers løser CPU-bound beregning: parsing af store datasæt, kryptografi, billedbehandling. Hvis en opgave tager 50+ ms og er CPU-intensiv (ikke venter på netværk) er Web Workers den rigtige løsning. Et langt database-kald løses med async/await — et 200ms JSON-parse løses med Web Workers.
- Er Web Workers relevante for SEO og Core Web Vitals?
- Indirekte men reelt. Web Workers forbedrer INP (Interaction to Next Paint) ved at reducere long tasks på main thread — og INP er en Core Web Vitals-rankingfaktor. Applikationer med tung JavaScript-beregning der blokerer brugerinteraktion i 200-500ms kan forbedre INP markant ved at flytte beregningen til Workers. Det er ikke en direkte crawling-SEO-faktor men en direkte rankingfaktor via Core Web Vitals.
- Hvad er Comlink og hvornår er det nyttigt?
- Comlink er Googles JavaScript-bibliotek der abstraherer Web Worker kommunikation til normale async funktionskald. I stedet for manuel postMessage-håndtering kan du kalde Worker-funktioner som om de er lokale async-funktioner. Det eliminerer en stor mængde boilerplate-kode og gør Workers langt mere vedligeholdelsesvenlige. Comlink er ideel til projekter der bruger Workers til komplekse beregningsopgaver med mange dataudvekslinger.
Placering i ordbogen
- Animation performance — Frame rate og jank-fri bevægelse
- Billedoptimering — Formater, størrelser og SEO
- Browser rendering pipeline — Fra HTML til pixels
- CLS-problemer — Årsager til Cumulative Layout Shift og løsninger
- Core Web Vitals — LCP, INP og CLS forklaret
- CSS — Cascading Style Sheets og SEO
- CSS containment — Isolér rendering og accelerér layout
- Font-optimering — Webfonts, FOUT og SEO
- HTTP/2 og HTTP/3 — Protokoller der eliminerer latency-overhead
- INP-optimering — Interaction to Next Paint og Core Web Vitals
- JavaScript bundle-optimering — Code splitting, tree shaking og analyse
- Kritisk renderingsti — Hvad browseren gør før du ser noget
- Latency — Forsinkelse i netværket og hvad du kan gøre ved det
- Lazy loading — Udskyd indlæsning af billeder og ressourcer
- LCP-optimering — Sådan forbedrer du Largest Contentful Paint
- Long Tasks og LoAF — Hvad blokerer main thread
- Navigation og resource timings — Browserens performance-API
- PageSpeed og SEO — Hastighed som rankingfaktor
- Performance budgets — Grænser der forhindrer regressioner
- Performance timings — Hvornår er det for langsomt?
- Resource hints — Preload, prefetch og preconnect til SEO
- Responsive images — srcset, sizes og art direction
- Responsivt design — Mobile-first og SEO
- RUM vs. syntetisk monitoring — To syn på web performance
- Service Workers — Offline caching og PWA performance
- Speculative loading — Prefetch og prerender af næste side
- Startup performance — Hurtig app-start og time to interactive
- Tredjeparts-scripts og performance — Impact og strategier
- Tredjepartsscripts — Analytics, ads og performance-konsekvenser
- TTFB og hosting — Server response time og SEO
- Video performance — Lazy loading, formater og indlæsningsstrategi
- Viewport tag — Meta viewport og mobil-rendering