Web Workers vs Service Workers: cosa sono e perché
Scopri cosa sono i Web Worker e i Service Worker, come differiscono e quando usare l'uno o l'altro per pagine più veloci, compiti in background, caching e supporto offline.

Web Workers vs Service Workers: panoramica rapida
I browser eseguono la maggior parte del tuo JavaScript sul thread principale—lo stesso contesto che gestisce input utente, animazioni e il disegno della pagina. Quando lì avviene lavoro pesante (parsing di grandi dati, elaborazione immagini, calcoli complessi), l'interfaccia può balbettare o "congelarsi". I worker servono a spostare certi compiti fuori dal thread principale o al di fuori del controllo diretto della pagina, così la tua app resta reattiva.
Il problema che risolvono i worker
Se la tua pagina è impegnata in una computazione di 200ms, il browser non può scorrere in modo fluido, rispondere ai click o mantenere le animazioni a 60fps. I worker aiutano permettendoti di eseguire lavoro in background mentre il thread principale si concentra sull'interfaccia.
Definizioni rapide
Un Web Worker è un thread JavaScript in background che crei da una pagina. È ottimo per compiti CPU-intensive che altrimenti bloccherebbero l'interfaccia.
Un Service Worker è un tipo speciale di worker che si pone tra la tua web app e la rete. Può intercettare le richieste, cachare risposte e abilitare funzionalità come supporto offline e notifiche push.
Un modello mentale semplice: “thread” vs “proxy di rete”
Pensa al Web Worker come a un aiutante che esegue calcoli in un'altra stanza. Gli invii un messaggio, lavora e ti risponde.
Pensa al Service Worker come a una guardia alla porta d'ingresso. Le richieste per pagine, script e chiamate API gli passano davanti, e può decidere se prendere dalla rete, servire dalla cache o rispondere in modo personalizzato.
Cosa imparerai in questo articolo
Alla fine saprai:
- quando un Web Worker è lo strumento giusto per le performance (e cosa non può accedere)
- cosa abilita un Service Worker per caching offline, aggiornamenti e comportamento PWA
- come il messaging (come
postMessage) si inserisce nel modello dei worker e perché la Cache Storage API è importante per l'offline
Questa panoramica stabilisce il “perché” e il modello mentale—poi entreremo nei dettagli su come si comporta ogni tipo di worker e dove si inserisce in progetti reali.
Perché i browser hanno i worker
Quando apri una pagina web, la maggior parte di ciò che percepisci accade sul thread principale. È responsabile di disegnare i pixel (rendering), reagire a tocchi e click (input) ed eseguire molto JavaScript.
Il thread principale è una cassa condivisa
Poiché rendering, gestione degli input e JavaScript spesso si alternano sullo stesso thread, un'attività lenta può far aspettare tutto il resto. Ecco perché i problemi di performance si manifestano spesso come problemi di reattività, non solo “codice lento”.
Come si presenta il blocco agli utenti:
- Scrolling che balbetta (jank)
- Pulsanti che non rispondono subito ai click
- Digitazione che rimane indietro rispetto alla tastiera
- Animazioni che si congelano per un istante
Async non significa parallelo
JavaScript offre molte API asincrone—fetch(), timer, eventi—che ti aiutano a evitare di restare in attesa passiva. Ma asincrono non vuol dire che il lavoro pesante venga eseguito contemporaneamente al rendering.
Se esegui una computazione costosa (elaborazione immagine, parsing di grandi JSON, crypto, filtraggi complessi) sul thread principale, continua a competere con gli aggiornamenti UI. L’asincrono può ritardare quando una cosa viene eseguita, ma potrebbe comunque girare sullo stesso thread principale e causare jank quando viene eseguito.
Dove si inseriscono i worker nell'architettura del browser
I worker esistono affinché i browser possano mantenere la pagina reattiva pur facendo lavoro significativo.
- Web Worker ti permettono di eseguire JavaScript su un thread di background per compiti CPU-intensive.
- Service Worker girano separatamente da qualsiasi pagina, agendo più come uno strato di rete e caching che può funzionare anche quando la pagina non è aperta.
In breve: i worker sono un modo per proteggere il thread principale così la tua app resta interattiva mentre fa lavoro reale in background.
Che cos'è un Web Worker?
Un Web Worker è un modo per eseguire JavaScript fuori dal thread principale. Invece di competere con il lavoro UI (rendering, scrolling, risposta ai click), un worker gira in un proprio thread di background così i compiti pesanti possono terminare senza far sembrare la pagina “bloccata”.
Pensalo così: la pagina resta concentrata sull'interazione utente, mentre il worker gestisce lavori CPU-intensive come il parsing di grandi file, il crunching di numeri o la preparazione di dati per grafici.
Dove viene eseguito
Un Web Worker gira in un thread separato con il proprio scope globale. Ha accesso a molte API web (timer, fetch in molti browser, crypto, ecc.), ma è intenzionalmente isolato dalla pagina.
Dedicated Worker vs Shared Worker
Esistono un paio di varianti comuni:
- Dedicated Worker: connesso a una singola pagina/tab. Quando quella pagina scompare, il worker tipicamente viene terminato.
- Shared Worker: può essere condiviso da più pagine/tab della stessa origine, utile per coordinare lavoro tra schede (ad esempio condividere una singola connessione o sincronizzare stato).
Se non hai mai usato i worker, la maggior parte degli esempi che vedrai sono Dedicated Worker.
Come comunicano i Web Worker
I worker non richiamano funzioni della pagina direttamente. La comunicazione avviene inviando messaggi:
- La pagina manda dati al worker con
postMessage(). - Il worker risponde con
postMessage()a sua volta. - I dati vengono trasferiti usando l'algoritmo structured clone, che supporta molti tipi incorporati (oggetti, array, stringhe, numeri, Map/Set, ArrayBuffer e altro).
Per grandi dati binari, spesso puoi migliorare le prestazioni trasferendo la proprietà di un ArrayBuffer (così non viene copiato), mantenendo il passaggio di messaggi veloce.
Limiti comuni (per progettazione)
Poiché un worker è isolato, ci sono alcuni vincoli chiave:
- Nessun accesso diretto al DOM: un worker non può leggere o modificare l'HTML, il CSS o il layout della pagina.
- Globali diversi: non hai
windowodocument. I worker girano sottoself(uno scope globale del worker), e le API disponibili possono differire dalla pagina principale. - Mentalità asincrona: tutto è basato su messaggi, quindi strutturi il codice intorno all'invio di lavoro e alla ricezione dei risultati.
Usato bene, un Web Worker è uno dei modi più semplici per migliorare le prestazioni del thread principale senza cambiare ciò che fa la tua app—solo dove avviene il lavoro pesante.
Quando usare i Web Worker (e quando no)
I Web Worker sono una buona scelta quando la tua pagina sembra “bloccata” perché troppo JavaScript gira sul thread principale. Il thread principale è anche responsabile delle interazioni utente e del rendering, quindi compiti pesanti lì possono causare jank, click ritardati e scrolling congelato.
I casi migliori per i Web Worker
Usa un Web Worker quando hai lavoro CPU-intensive che non necessita di accesso diretto al DOM:
- Calcoli pesanti: simulazioni, elaborazioni, crunching numerico.
- Parsing e trasformazione: parsing di grandi JSON, CSV, validazioni di schema.
- Compressione / decompressione: workload tipo zip/gzip, encoding/decoding.
- Elaborazione immagini: ridimensionamento, filtri, generazione di miniature (spesso abbinato a OffscreenCanvas nei browser che lo supportano).
Un esempio pratico: se ricevi un grande payload JSON e il parsing causa stuttering dell'interfaccia, sposta il parsing in un worker e poi rimanda il risultato.
Suggerimenti per la gestione dei dati (per velocità)
La comunicazione con un worker avviene tramite postMessage. Per grandi dati binari, preferisci oggetti transferabili (come ArrayBuffer) così il browser può trasferire la proprietà della memoria al worker invece di copiarla.
// main thread
worker.postMessage(buffer, [buffer]); // trasferisce l'ArrayBuffer
Questo è particolarmente utile per buffer audio, bytes di immagini o altri grandi blocchi di dati.
Quando non usare i Web Worker
I worker hanno overhead: file extra, passaggio di messaggi e un flusso di debug diverso. Evitali quando:
- Il compito è piccolo (millisecondi) e si verifica raramente.
- Il lavoro richiede letture/scritture DOM frequenti (i worker non possono toccare il DOM).
- Hai bisogno di latenza ultra-bassa per scambi continui; il ping-pong costante con
postMessagepuò annullare il beneficio.
Una regola pratica
Se un compito può causare una pausa percepibile (spesso ~50ms+) e può essere espresso come “input → compute → output” senza accesso al DOM, un Web Worker vale di solito la pena. Se è principalmente aggiornamenti UI, resta sul thread principale e ottimizza lì.
Che cos'è un Service Worker?
Un Service Worker è un file JavaScript speciale che gira in background nel browser e agisce come uno strato di rete programmabile per il tuo sito. Invece di eseguire nel contesto della pagina, si pone tra la tua web app e la rete, permettendoti di decidere cosa succede quando l'app richiede risorse (HTML, CSS, chiamate API, immagini).
Ciclo di vita di base (register → install → activate → control)
Un Service Worker ha un ciclo di vita separato da qualsiasi tab:
- Register: la pagina dice al browser “questo sito ha un service worker” (di solito dal JS principale).
- Install: il browser lo scarica ed esegue un passo di installazione, spesso usato per precachare file importanti.
- Activate: il nuovo worker prende il controllo, tipicamente dopo la chiusura delle vecchie tab o quando è sicuro sostituire la versione precedente.
- Control: una volta attivo, può “controllare” le pagine nel suo scope e iniziare a intercettare le richieste.
Poiché può essere fermato e riavviato in qualsiasi momento, trattalo come uno script guidato dagli eventi: fai il lavoro velocemente, salva stato in storage persistente ed evita di presumere che sia sempre in esecuzione.
Regole di scope e origine (livello alto)
I Service Worker sono limitati alla stessa origine (stesso dominio/protocollo/porta) e controllano solo le pagine nel loro scope—di solito la cartella in cui il file del worker è servito (e sotto). Richiedono anche HTTPS (eccetto localhost) perché possono influenzare le richieste di rete.
API principali che vedrai spesso
- Fetch event: intercetta le richieste e decide se usare la rete, una cache o una risposta personalizzata.
- Cache Storage API: memorizza e recupera risposte cache per l'uso offline e le performance.
- Clients API: comunica con e gestisce tab/finestre aperte che il worker controlla.
A cosa servono i Service Worker
Un Service Worker serve principalmente a porsi tra la tua web app e la rete. Può decidere quando usare la rete, quando usare dati cacheati e quando fare un po' di lavoro in background—senza bloccare la pagina.
Supporto offline (caching intelligente)
Il compito più comune è abilitare esperienze offline o con connessione debole cachando asset e risposte.
Alcune strategie pratiche di caching che vedrai:
- Cache-first: ideale per file statici (CSS, JS, loghi). Veloce, funziona offline.
- Network-first: adatto a contenuti che cambiano spesso (news, feed). Fa fallback sulla cache quando offline.
- Stale-while-revalidate: mostra contenuto cacheato immediatamente, poi lo aggiorna in background per la prossima volta.
Questo si implementa di solito con la Cache Storage API e la gestione dell'evento fetch.
Visite ripetute più veloci
I Service Worker possono migliorare la percezione di velocità nelle visite successive tramite:
- Precaching: salvare i file indispensabili dell'app durante l'installazione (spesso chiamato app shell).
- Runtime caching: cachare pagine o risposte API man mano che l'utente naviga.
Il risultato sono meno richieste di rete, avvio più rapido e prestazioni più coerenti con connessioni instabili.
Funzionalità in background (dove supportate)
I Service Worker possono alimentare funzionalità in background come push notifications e background sync (il supporto varia tra browser e piattaforme). Ciò significa che puoi notificare gli utenti o ritentare una richiesta fallita più tardi—even se la pagina non è aperta.
Mattoni per le PWA
Se stai costruendo una Progressive Web App, i Service Worker sono una parte centrale per:
- Installabilità (insieme a un web app manifest)
- Pagine offline affidabili (es. fallback amichevole)
- Il modello app shell per una navigazione più reattiva
Differenze chiave: Web Worker vs Service Worker
Se ricordi una cosa: i Web Worker aiutano la tua pagina a fare lavoro pesante senza bloccare l'interfaccia, mentre i Service Worker aiutano la tua app a controllare le richieste di rete e a comportarsi come un'app installabile (PWA).
Dove girano (a cosa servono)
Un Web Worker è per compiti CPU-intensive—parsing di grandi dati, generazione miniature, crunching numerico—così il thread principale resta reattivo.
Un Service Worker è per gestione richieste e compiti legati al ciclo di vita dell'app—supporto offline, strategie di caching, background sync e notifiche push. Può stare tra la tua app e la rete.
Durata e “chi lo possiede”
Un Web Worker è tipicamente legato a una pagina/tab. Quando la pagina scompare, il worker di solito scompare (a meno di casi speciali come SharedWorker).
Un Service Worker è guidato dagli eventi. Il browser può avviarlo per gestire un evento (come una fetch o un push) e poi fermarlo quando è inattivo. Ciò significa che può girare anche quando non c'è nessuna tab aperta, fintanto che un evento lo risveglia.
Accesso e controllo della rete
Un Web Worker non può intercettare le richieste di rete fatte dalla pagina. Può usare fetch() per ottenere dati, ma non può riscrivere, cachare o servire risposte per altre parti del sito.
Un Service Worker può intercettare le richieste di rete (tramite l'evento fetch), decidere se andare in rete, rispondere dalla cache o restituire un fallback.
Storage e caching
Un Web Worker non gestisce il caching HTTP della tua app.
Un Service Worker usa comunemente la Cache Storage API per memorizzare e servire coppie request/response—questa è la base per il caching offline e i caricamenti “istantanei” nelle visite ripetute.
Come configurarli (passi ad alto livello)
Far funzionare un worker riguarda soprattutto dove gira e come viene caricato. I Web Worker vengono creati direttamente dallo script della pagina. I Service Worker vengono installati dal browser e si pongono “davanti” alle richieste di rete del tuo sito.
Web Worker: crealo dalla pagina
Un Web Worker nasce quando la tua pagina ne crea uno. Indichi un file JavaScript separato e comunichi via postMessage.
// main.js (in esecuzione sulla pagina)
const worker = new Worker('/workers/resize-worker.js', { type: 'module' });
worker.postMessage({ action: 'start', payload: { /* ... */ } });
worker.onmessage = (event) => {
console.log('From worker:', event.data);
};
Un buon modello mentale: il file del worker è un normale URL di script che la pagina può recuperare, ma viene eseguito fuori dal thread principale.
Service Worker: registralo (una sola volta) e lascia che il browser lo installi
I Service Worker devono essere registrati da una pagina che l'utente visita:
// main.js
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
Dopo la registrazione, il browser gestisce il ciclo install/activate. Il tuo sw.js può ascoltare eventi come install, activate e fetch.
Perché i Service Worker richiedono HTTPS
I Service Worker possono intercettare richieste di rete e cachare risposte. Se la registrazione fosse permessa su HTTP, un attaccante in rete potrebbe sostituire sw.js con uno malevolo e controllare le visite future. HTTPS (o http://localhost per sviluppo) protegge lo script e il traffico che può influenzare.
Mentalità di versioning: tratta i file worker come “release” distribuibili
I browser cachano e aggiornano i worker in modo diverso dagli script di pagina. Pianifica gli aggiornamenti:
- Cambia il file quando il comportamento cambia (spesso deployando un nuovo
sw.js/bundle worker). - Nei Service Worker, aspetta un flusso di “update”: un nuovo worker si installa e poi si attiva quando è sicuro.
- Quando cambi le regole di caching, includi logica di cleanup durante l'activation così le cache vecchie non restano.
Se vuoi una strategia di rollout più morbida, vedi /blog/debugging-workers per abitudini di test che catturano gli edge case di aggiornamento presto.
Domande frequenti
How do I decide whether I need a Web Worker?
Usa un Web Worker quando hai del lavoro CPU-intensive che può essere espresso come input → compute → output e non necessita del DOM.
Sono adatti il parsing/trasformazione di payload grandi, compressione, crypto, elaborazione immagine/audio e filtri complessi. Se il lavoro è principalmente aggiornamenti UI o letture/scritture frequenti del DOM, un worker non aiuterà (e comunque non può accedere al DOM).
How do I decide whether I need a Service Worker?
Usa un Service Worker quando hai bisogno di controllo sulla rete: supporto offline, strategie di caching, visite più veloci, instradamento delle richieste e (dove supportato) push/background sync.
Se il tuo problema è “l'interfaccia si blocca mentre calcola”, è un caso per Web Worker. Se il problema è “i caricamenti sono lenti/offline non funziona”, è un caso per Service Worker.
Do Web Workers require a Service Worker (or vice versa)?
No. Web Worker e Service Worker sono funzionalità indipendenti.
- Web Worker: creato da una pagina per calcoli in background.
- Service Worker: installato/attivato dal browser per intercettare richieste e gestire il caching.
Puoi usarne uno solo, oppure combinarli quando l'app ha bisogno sia di compute che di funzionalità offline/rete.
What’s the biggest difference in lifetime between Web Workers and Service Workers?
Principalmente ambito e durata.
- Un Web Worker è di solito legato a una pagina/tab (soprattutto un Dedicated Worker) e normalmente termina quando la pagina si chiude.
- Un Service Worker è guidato dagli eventi e può risvegliarsi per gestire eventi (come
fetch) anche quando non c'è nessuna pagina aperta, poi si chiude quando è inattivo.
Can a Web Worker access or modify the DOM?
No. I Web Worker non hanno accesso a window/document.
Se devi influenzare l'interfaccia, invia i dati al thread principale con postMessage() e aggiorna il DOM nel codice della pagina. Mantieni il worker concentrato sulla pura computazione.
Can a Service Worker access the DOM?
No. I Service Worker non hanno accesso al DOM.
Per influenzare ciò che l'utente vede, comunica con le pagine controllate tramite messaging (ad esempio usando la Clients API + postMessage()), e lascia che sia la pagina ad aggiornare l'interfaccia.
What’s the best way to send data to a Web Worker efficiently?
Usa postMessage() su entrambi i lati.
- Main thread → worker:
worker.postMessage(data) - Worker → main thread:
self.postMessage(result)
Per dati binari grandi, prediligi i transferable (come ArrayBuffer) per evitare copie:
worker.postMessage(buffer, [buffer]);
How does offline caching work with a Service Worker?
I Service Worker si pongono tra la tua app e la rete e possono rispondere alle richieste usando la Cache Storage API.
Strategie comuni:
- Cache-first: ottimo per asset statici
- Network-first: migliore per dati che cambiano spesso
- Stale-while-revalidate: risposta veloce ora, aggiornamento in background
Scegli una strategia per tipo di risorsa (app shell vs dati API), non una regola unica globale.
Can I use a Web Worker and Service Worker together in the same app?
Sì, ma tieni chiare le responsabilità.
Un pattern comune è:
- Web Worker: compute (es. generare miniature, normalizzare JSON grandi)
- Service Worker: cache/serve (memorizzare i risultati per l'accesso offline e caricamenti rapidi)
- Main thread: UI
Questo evita di mescolare la logica UI nei contesti di background e mantiene le performance prevedibili.
What are the quickest debugging steps when workers don’t behave as expected?
Usa la superficie DevTools corretta per ciascuno.
- Web Worker: controlla il target worker in DevTools (Sources/Console context), imposta breakpoint in
onmessagee profila per confermare che il thread principale resta reattivo. - Service Worker: usa il pannello Application per ispezionare registrazione/scope, abilita “Update on reload” e resetta lo stato con “Unregister” o “Skip waiting”.
Per i bug di caching, verifica sempre cosa viene effettivamente servito (rete vs cache) e testa offline/throttling.