Service Workers — Offline caching og PWA performance
Service Workers intercepter netværkskald og cacher ressourcer lokalt. Returnerende brugere oplever øjeblikkelig indlæsning — TTFB og LCP reduceres til nul for cachede sider.
En Service Worker er en scriptbar netværks-proxy der kører i baggrunden. Den intercept-er alle netværkskald fra din side og kan svare med cachede ressourcer, modificere requests eller fallback til en offline-side. For returnerende brugere er det den mest effektive performance-teknik: TTFB og LCP reduceres til nul for ressourcer der serveres fra Service Worker-cachen.
Livscyklus
Service Workers gennemgår en defineret livscyklus:
- Registration — siden registrerer Service Worker-scriptet
- Installation — SW downloader og cacher definerede ressourcer (precaching)
- Activation — SW overtager kontrol over siden
- Fetch interception — SW intercepter fremtidige netværkskald
// Registrer Service Worker
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js');
});
}
Caching-strategier
Der er etablerede strategier for hvornår og hvad der caches:
Cache First (cache falling back to network)
Servér fra cache. Netværket er fallback. Optimal for statiske assets der sjældent ændres:
// sw.js
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((cached) => {
return cached || fetch(event.request);
})
);
});
Network First (network falling back to cache)
Forsøg netværket. Fald tilbage til cache hvis netværket fejler. Optimal for API-kald og dynamisk indhold:
self.addEventListener('fetch', (event) => {
event.respondWith(
fetch(event.request).catch(() => caches.match(event.request))
);
});
Stale While Revalidate
Servér cached version øjeblikkeligt. Opdatér cache i baggrunden. Balancerer friskhed og hastighed:
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.open('v1').then((cache) => {
return cache.match(event.request).then((cached) => {
const networkFetch = fetch(event.request).then((response) => {
cache.put(event.request, response.clone());
return response;
});
return cached || networkFetch;
});
})
);
});
Precaching ved installation
Cache kritiske ressourcer ved SW-installation — de er tilgængelige øjeblikkeligt ved første visit efter:
const CACHE_NAME = 'v1';
const PRECACHE_URLS = ['/', '/offline.html', '/styles.css', '/app.js'];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => cache.addAll(PRECACHE_URLS))
);
});
Offline fallback
En offline-side der vises når brugeren er offline og siden ikke er cached:
self.addEventListener('fetch', (event) => {
if (event.request.mode === 'navigate') {
event.respondWith(
fetch(event.request).catch(() => caches.match('/offline.html'))
);
}
});
Workbox — praktisk Service Worker bibliotek
Manuel Service Worker-implementering er fejlprone. Workbox (Google) abstraherer caching-strategier til deklarative konfigurationer:
import { registerRoute } from 'workbox-routing';
import { StaleWhileRevalidate, CacheFirst } from 'workbox-strategies';
registerRoute(
({ request }) => request.destination === 'image',
new CacheFirst({ cacheName: 'images' })
);
registerRoute(
({ url }) => url.pathname.startsWith('/api/'),
new StaleWhileRevalidate({ cacheName: 'api-cache' })
);
Performance-implikationen
For returnerende brugere serveret fra Service Worker cache:
- TTFB: ~0ms (lokal cache)
- LCP: reduceres markant — kritiske assets er lokale
- Offline: siden fungerer uden netværk
Google Lighthouse auditerer Service Worker-implementering under PWA-kategorien. En velfungerende SW forbedrer ikke direkte Core Web Vitals-scores i lab-tests (Lighthouse kører som first visit) men har markant effekt på field data for returnerende brugere. → 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
- 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
- Web Workers — Parallel JavaScript uden main thread-blokning
Ofte stillede spørgsmål
- Hvad er en Service Worker?
- En Service Worker er et JavaScript-script der kører i en separat browser-thread og fungerer som en proxy mellem webapplikationen og netværket. Den kan intercepte, cache og manipulere netværkskald — også når siden er lukket. Service Workers kræver HTTPS (undtagen localhost) og er en del af Progressive Web App-specifikationen.
- Hvad er forskellen på Service Worker caching og HTTP caching?
- HTTP caching styres af Cache-Control-headeren og er browser-kontrolleret. Service Worker caching er applikations-kontrolleret via Cache Storage API — du bestemmer præcist hvilke ressourcer der caches, hvornår de opdateres og hvad der serveres når netværket er utilgængeligt. Service Workers kan servere offline fallback-sider, HTTP caching kan ikke.
- Påvirker Service Workers SEO og Googlebots crawling?
- Service Workers kan i princippet intercepte Googlebots requests og servere andet indhold end det brugere ser — det er cloaking og en overtrædelse af Googles retningslinjer. I praksis kører Googlebot med fetch-mode 'navigate' og ignorerer typisk Service Workers i crawl-fasen. Men implementeringer der returnerer cached stale-content til Googlebot mens brugere ser frisk indhold kan skabe forvirring. Hold Service Worker-logik separat fra indholdslevering til Googlebot.
- Hvad er Stale While Revalidate og hvornår er det bedst?
- Stale While Revalidate serverer cached version øjeblikkeligt og opdaterer cachen i baggrunden via et parallelt netværkskald. Brugeren oplever nul ventetid men ser muligvis indhold der er op til én cache-periode gammelt. Det er den bedste strategi til ressourcer der ændres jævnligt men ikke behøver at være 100% friske — blogindlæg, kategori-sider, ikke-kritiske API-kald. Til prisinformation eller lagerstatus er Network First bedre.
- Hvad er Workbox og hvornår er det værd at bruge?
- Workbox er Googles JavaScript-bibliotek der abstraherer Service Worker-implementering til deklarative konfigurationer. Det håndterer precaching, caching-strategier, opdateringscyklusser og cache-invalidering uden at du skriver boilerplate-kode manuelt. Workbox er standardanbefalingen for alle produktionsprojekter — manuel Service Worker-implementering er fejlpron og svær at vedligeholde. Workbox integrerer direkte med Webpack, Vite og Rollup via plugins.
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
- 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
- Web Workers — Parallel JavaScript uden main thread-blokning