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.

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.
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.
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.
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.
Alla fine saprai:
postMessage) si inserisce nel modello dei worker e perché la Cache Storage API è importante per l'offlineQuesta 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.
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.
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:
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.
I worker esistono affinché i browser possano mantenere la pagina reattiva pur facendo lavoro significativo.
In breve: i worker sono un modo per proteggere il thread principale così la tua app resta interattiva mentre fa lavoro reale in background.
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.
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.
Esistono un paio di varianti comuni:
Se non hai mai usato i worker, la maggior parte degli esempi che vedrai sono Dedicated Worker.
I worker non richiamano funzioni della pagina direttamente. La comunicazione avviene inviando messaggi:
postMessage().postMessage() a sua volta.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.
Poiché un worker è isolato, ci sono alcuni vincoli chiave:
window o document. I worker girano sotto self (uno scope globale del worker), e le API disponibili possono differire dalla pagina principale.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.
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.
Usa un Web Worker quando hai lavoro CPU-intensive che non necessita di accesso diretto al DOM:
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.
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.
I worker hanno overhead: file extra, passaggio di messaggi e un flusso di debug diverso. Evitali quando:
postMessage può annullare il beneficio.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ì.
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).
Un Service Worker ha un ciclo di vita separato da qualsiasi tab:
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.
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.
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.
Il compito più comune è abilitare esperienze offline o con connessione debole cachando asset e risposte.
Alcune strategie pratiche di caching che vedrai:
Questo si implementa di solito con la Cache Storage API e la gestione dell'evento fetch.
I Service Worker possono migliorare la percezione di velocità nelle visite successive tramite:
Il risultato sono meno richieste di rete, avvio più rapido e prestazioni più coerenti con connessioni instabili.
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.
Se stai costruendo una Progressive Web App, i Service Worker sono una parte centrale per:
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).
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.
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.
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.
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.
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.
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.
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.
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.
I browser cachano e aggiornano i worker in modo diverso dagli script di pagina. Pianifica gli aggiornamenti:
sw.js/bundle worker).Se vuoi una strategia di rollout più morbida, vedi /blog/debugging-workers per abitudini di test che catturano gli edge case di aggiornamento presto.
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).
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.
No. Web Worker e Service Worker sono funzionalità indipendenti.
Puoi usarne uno solo, oppure combinarli quando l'app ha bisogno sia di compute che di funzionalità offline/rete.
Principalmente ambito e durata.
fetch) anche quando non c'è nessuna pagina aperta, poi si chiude quando è inattivo.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.
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.
Usa postMessage() su entrambi i lati.
worker.postMessage(data)self.postMessage(result)Per dati binari grandi, prediligi i transferable (come ArrayBuffer) per evitare copie:
I Service Worker si pongono tra la tua app e la rete e possono rispondere alle richieste usando la Cache Storage API.
Strategie comuni:
Scegli una strategia per tipo di risorsa (app shell vs dati API), non una regola unica globale.
Sì, ma tieni chiare le responsabilità.
Un pattern comune è:
Questo evita di mescolare la logica UI nei contesti di background e mantiene le performance prevedibili.
Usa la superficie DevTools corretta per ciascuno.
onmessage e profila per confermare che il thread principale resta reattivo.Per i bug di caching, verifica sempre cosa viene effettivamente servito (rete vs cache) e testa offline/throttling.
worker.postMessage(buffer, [buffer]);