Comprenez ce que sont les Web Workers et les Service Workers, en quoi ils diffèrent et quand utiliser chacun pour des pages plus rapides, des tâches en arrière-plan, la mise en cache et le support hors ligne.

Les navigateurs exécutent la plupart de votre JavaScript sur le thread principal—le même endroit qui gère les saisies utilisateur, les animations et le rendu de la page. Quand un travail lourd s'y produit (parsing de gros jeux de données, traitement d'images, calculs complexes), l'interface peut saccader ou « geler ». Les workers existent pour déplacer certaines tâches hors du thread principal ou en dehors du contrôle direct de la page, afin que votre app reste réactive.
Si votre page est occupée à faire un calcul de 200 ms, le navigateur ne peut pas faire défiler en douceur, répondre aux clics ou maintenir les animations à 60 fps. Les workers aident en vous permettant d'effectuer du travail en arrière-plan pendant que le thread principal se concentre sur l'interface.
Un Web Worker est un thread JavaScript en arrière-plan que vous créez depuis une page. Il est idéal pour des tâches lourdes en CPU qui bloqueraient autrement l'interface.
Un Service Worker est un type spécial de worker qui se place entre votre application web et le réseau. Il peut intercepter des requêtes, mettre en cache des réponses et activer des fonctionnalités comme le support hors ligne et les notifications push.
Pensez au Web Worker comme à un assistant qui fait des calculs dans une autre pièce. Vous lui envoyez un message, il travaille, puis il renvoie un message.
Pensez au Service Worker comme à un portier à la porte d'entrée. Les requêtes pour des pages, des scripts et des appels d'API passent devant lui, et il peut décider de récupérer depuis le réseau, servir depuis le cache, ou répondre d'une manière personnalisée.
À la fin, vous saurez :
postMessage) s'insère dans le modèle des workers, et pourquoi la Cache Storage API compte pour le hors ligneCet aperçu pose le « pourquoi » et le modèle mental—ensuite nous plongerons dans le comportement de chaque type de worker et où les utiliser dans des projets réels.
Quand vous ouvrez une page web, la plupart de ce que vous « ressentez » se passe sur le thread principal. Il est responsable d'afficher les pixels (rendu), de réagir aux taps et clics (saisie), et d'exécuter beaucoup de JavaScript.
Parce que le rendu, la gestion des entrées et JavaScript s'exécutent souvent à tour de rôle sur le même thread, une tâche lente peut faire attendre tout le reste. C'est pourquoi les problèmes de performance se manifestent souvent comme des problèmes de réactivité, pas seulement du « code lent ».
Ce que « bloquer » donne à l'utilisateur :
JavaScript propose de nombreuses API asynchrones—fetch(), timers, événements—qui aident à éviter d'attendre. Mais l'asynchrone ne fait pas disparaître le fait que du travail lourd puisse s'exécuter sur le même thread que le rendu.
Si vous faites un calcul coûteux (traitement d'image, parsing d'un gros JSON, crypto, filtrage complexe) sur le thread principal, il rivalise toujours avec les mises à jour de l'UI. « Asynchrone » peut différer quand le code s'exécute, mais il peut toujours s'exécuter sur le même thread principal et provoquer des janks lorsqu'il s'exécute.
Les workers existent pour que les navigateurs puissent garder la page réactive tout en faisant un travail significatif.
En bref : les workers protègent le thread principal pour que votre application reste interactive tout en effectuant un vrai travail en arrière-plan.
Un Web Worker est un moyen d'exécuter du JavaScript hors du thread principal. Au lieu de rivaliser avec le travail UI (rendu, défilement, réponse aux clics), un worker s'exécute dans son propre thread en arrière-plan afin que les tâches lourdes puissent se terminer sans donner l'impression que la page est « bloquée ».
Pensez-y ainsi : la page reste concentrée sur l'interaction utilisateur, tandis que le worker gère des travaux lourds en CPU comme le parsing d'un gros fichier, le crunching de nombres ou la préparation de données pour des graphiques.
Un Web Worker s'exécute dans un thread séparé avec son propre scope global. Il a toujours accès à de nombreuses API web (timers, fetch dans de nombreux navigateurs, crypto, etc.), mais il est volontairement isolé de la page.
Il existe quelques variantes courantes :
Si vous n'avez jamais utilisé les workers, la plupart des exemples sont des dedicated workers.
Les workers n'appellent pas de fonctions directement dans votre page. La communication se fait via l'envoi de messages :
postMessage().\n- Le worker répond également avec postMessage().\n- Les données sont transférées en utilisant l'algorithme de structured clone, qui supporte de nombreux types natifs (objets, tableaux, chaînes, nombres, Maps/Sets, ArrayBuffers, etc.).Pour de grosses données binaires, vous pouvez souvent améliorer la performance en transférant la propriété d'un ArrayBuffer (pour éviter la copie), ce qui garde le passage de messages rapide.
Parce qu'un worker est isolé, il existe quelques contraintes clés :
window ou document. Les workers s'exécutent sous self (un scope global worker), et les API disponibles peuvent différer de la page principale.\n- Esprit asynchrone : tout est basé sur des messages, vous structurez donc votre code autour de l'envoi de travail et de la réception des résultats.Bien utilisé, un Web Worker est l'un des moyens les plus simples d'améliorer la performance du thread principal sans changer le comportement de votre application—seulement l'endroit où le travail coûteux s'exécute.
Les Web Workers conviennent quand votre page semble « bloquée » parce que du JavaScript fait trop de travail sur le thread principal. Le thread principal gère aussi les interactions utilisateur et le rendu, donc des tâches lourdes peuvent entraîner du jank, des clics retardés et un défilement figé.
Utilisez un Web Worker quand vous avez du travail intensif en CPU qui n'a pas besoin d'accès direct au DOM :
Un exemple pratique : si vous recevez un grand payload JSON et que son parsing provoque des saccades de l'UI, déplacez le parsing dans un worker, puis renvoyez le résultat.
La communication avec un worker se fait via postMessage. Pour de grandes données binaires, préférez les objets transférables (comme ArrayBuffer) afin que le navigateur puisse transférer la propriété mémoire au worker au lieu de la copier.
// main thread
worker.postMessage(buffer, [buffer]); // transfère l'ArrayBuffer
C'est particulièrement utile pour des buffers audio, des octets d'image, ou d'autres gros blocs de données.
Les workers ont un coût : fichiers supplémentaires, passage de messages, et un flux de débogage différent. Évitez-les quand :
postMessage peut annihiler le bénéfice.Si une tâche peut provoquer une pause perceptible (souvent ~50 ms+) et peut s'exprimer comme « entrée → calcul → sortie » sans accès au DOM, un Web Worker en vaut généralement la peine. Si c'est principalement des mises à jour UI, restez sur le thread principal et optimisez là-bas.
Un Service Worker est un fichier JavaScript spécial qui s'exécute en arrière-plan dans le navigateur et agit comme une couche réseau programmable pour votre site. Au lieu de s'exécuter dans la page elle-même, il se place entre votre application web et le réseau, vous permettant de décider de ce qui se passe quand l'application demande des ressources (HTML, CSS, appels API, images).
Un Service Worker a un cycle de vie séparé de n'importe quel onglet :
Comme il peut être arrêté et redémarré à tout moment, traitez-le comme un script piloté par des événements : faites le travail rapidement, stockez l'état dans un stockage persistant, et n'assumez pas qu'il tourne en permanence.
Les Service Workers sont restreints à la même origine (même domaine/protocole/port) et ne contrôlent que les pages sous leur scope—généralement le dossier où le fichier worker est servi (et en dessous). Ils nécessitent aussi HTTPS (sauf localhost) car ils peuvent affecter les requêtes réseau.
Un Service Worker sert principalement à se placer entre votre application web et le réseau. Il peut décider quand utiliser le réseau, quand utiliser des données mises en cache, et effectuer un peu de travail en arrière-plan—sans bloquer la page.
La tâche la plus courante est d'activer des expériences hors ligne ou pour connexions faibles en mettant en cache des assets et des réponses.
Quelques stratégies de mise en cache pratiques :
Ceci s'implémente généralement avec la Cache Storage API et le traitement de l'événement fetch.
Les Service Workers peuvent améliorer la vitesse perçue lors des retours en :
Le résultat : moins de requêtes réseau, démarrage plus rapide et performances plus constantes sur des connexions instables.
Les Service Workers peuvent alimenter des capacités en arrière-plan comme les notifications push et la synchronisation en arrière-plan (le support varie selon le navigateur et la plateforme). Cela signifie que vous pouvez notifier les utilisateurs ou réessayer une requête échouée plus tard—même si la page n'est pas ouverte.
Si vous construisez une progressive web app, les Service Workers sont un pilier derrière :
Si vous ne retenez qu'une chose : les Web Workers aident votre page à effectuer du travail lourd sans geler l'UI, tandis que les Service Workers aident votre application à contrôler les requêtes réseau et à se comporter comme une app installable (PWA).
Un Web Worker sert pour des tâches lourdes en CPU—parser de grands fichiers, générer des vignettes, crunching de nombres—pour que le thread principal reste réactif.
Un Service Worker sert pour le traitement des requêtes et les tâches liées au cycle de vie de l'app—support hors ligne, stratégies de cache, synchronisation en arrière-plan et notifications push. Il peut se placer entre votre application et le réseau.
Un Web Worker est typiquement lié à une page/onglet. Quand la page disparaît, le worker s'arrête (sauf cas spéciaux comme SharedWorker).
Un Service Worker est piloté par les événements. Le navigateur peut le démarrer pour traiter un événement (comme une requête fetch ou un push), puis l'arrêter quand il est inactif. Cela signifie qu'il peut fonctionner même quand aucun onglet n'est ouvert, tant qu'un événement le réveille.
Un Web Worker ne peut pas intercepter les requêtes réseau faites par la page. Il peut faire des fetch(), mais il ne peut pas réécrire, mettre en cache ou servir des réponses pour d'autres parties de votre site.
Un Service Worker peut intercepter les requêtes réseau (via l'événement fetch), décider d'aller sur le réseau, répondre depuis le cache, ou renvoyer une page de secours.
Un Web Worker ne gère pas le cache HTTP de votre app.
Un Service Worker utilise couramment la Cache Storage API pour stocker et servir des paires requête/réponse—fondation de la mise en cache hors ligne et des chargements « instantanés » lors de visites répétées.
Faire tourner un worker revient surtout à savoir d'où il s'exécute et comment il est chargé. Les Web Workers sont créés directement par un script de page. Les Service Workers sont enregistrés par la page et s'installent via le navigateur pour se placer « devant » les requêtes réseau de votre site.
Un Web Worker naît quand votre page en crée un. Vous pointez vers un fichier JavaScript séparé, puis communiquez via postMessage.
// main.js (exécuté sur la page)
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 bon modèle mental : le fichier worker est simplement un autre URL de script que votre page peut récupérer, mais il s'exécute hors du thread principal.
Les Service Workers doivent être enregistrés depuis une page que l'utilisateur visite :
// main.js
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
Après l'enregistrement, le navigateur gère le cycle install/activate. Votre sw.js peut écouter des événements comme install, activate et fetch.
Les Service Workers peuvent intercepter les requêtes réseau et mettre en cache des réponses. Si l'enregistrement était autorisé en HTTP, un attaquant réseau pourrait remplacer un sw.js malveillant et contrôler les visites futures. HTTPS (ou http://localhost pour le développement) protège le script et le trafic qu'il peut influencer.
Les navigateurs mettent en cache et mettent à jour les workers différemment des scripts de page normaux. Prévoyez des mises à jour :
sw.js/bundle worker).\n- Dans les Service Workers, attendez-vous à un flux d'« update » : un nouveau worker s'installe, puis s'active quand c'est sûr.\n- Quand vous changez les règles de cache, incluez une logique de nettoyage lors de l'activation pour que les anciens caches ne restent pas.Si vous voulez une stratégie de déploiement plus douce, voyez /blog/debugging-workers pour des habitudes de test qui attrapent tôt les cas limites d'update.
Les workers échouent différemment du JavaScript « normal » : ils s'exécutent dans des contextes séparés, ont leur propre console, et peuvent être redémarrés par le navigateur. Une routine de débogage solide vous fera gagner des heures.
Ouvrez DevTools et cherchez les cibles spécifiques aux workers. Dans Chrome/Edge, vous verrez souvent les workers listés sous Sources (ou via l'entrée « Dedicated worker ») et dans le sélecteur de contexte de la Console.
Utilisez les mêmes outils que sur le thread principal :
onmessage et les fonctions longues.\n- Profilage de performance : enregistrez une trace Performance et vérifiez que le thread principal reste réactif pendant que le worker fait le travail.Si des messages semblent « perdus », inspectez les deux côtés : vérifiez que vous appelez worker.postMessage(...), que le worker a self.onmessage = ..., et que la forme du message correspond.
Les Service Workers se déboguent mieux dans le panneau Application :
Surveillez aussi la Console pour des erreurs d'install/activate/fetch—elles expliquent souvent pourquoi la mise en cache ou le comportement hors ligne ne fonctionne pas.
Les problèmes de cache sont la principale source de pertes de temps : mettre en cache les mauvais fichiers (ou trop agressivement) peut garder de l'HTML/JS ancien. Pendant les tests, effectuez un hard reload et confirmez ce qui est réellement servi depuis le cache.
Pour des tests réalistes, utilisez DevTools pour :
Si vous itérez rapidement sur une PWA, il peut être utile de générer une app de base propre (avec un Service Worker et une sortie de build prévisibles) puis d'affiner les stratégies de cache depuis là. Des plateformes comme Koder.ai peuvent aider pour ce type d'expérimentation : vous pouvez prototyper une app React depuis une invite, exporter le code source, puis ajuster votre configuration de workers et vos règles de cache avec un retour plus rapide.
Les workers peuvent rendre les apps plus fluides et plus capables, mais ils changent l'endroit où le code s'exécute et ce à quoi il peut accéder. Un rapide contrôle sécurité/vie privée/performance vous évitera des bugs surprenants—et des utilisateurs mécontents.
Les Web Workers et les Service Workers sont restreints par la same-origin policy : ils ne peuvent interagir directement qu'avec des ressources de la même origine (même schéma/hôte/port) sauf si le serveur autorise l'accès cross-origin via CORS. Cela empêche un worker de tirer discrètement des données d'un autre site et de les mélanger dans votre app.
Les Service Workers ont des garde-fous supplémentaires : ils nécessitent généralement HTTPS (ou localhost en développement) car ils peuvent intercepter des requêtes réseau. Traitez-les comme du code privilégié : limitez les dépendances, évitez le chargement dynamique de code, et versionnez la logique de cache pour que d'anciens caches ne servent pas des fichiers périmés.
Les fonctionnalités en arrière-plan doivent rester prévisibles. Les notifications push sont puissantes, mais les popups d'autorisation se prêtent facilement à l'abus.
Demandez la permission seulement quand il y a un bénéfice clair (par exemple après qu'un utilisateur a activé des alertes dans les paramètres), et expliquez ce qu'il recevra. Si vous synchronisez ou préchargez des données en arrière-plan, communiquez-le simplement—les utilisateurs remarquent une activité réseau inattendue ou des notifications.
Les workers ne sont pas « gratuits » en termes de performance. Leur surutilisation peut se retourner contre vous :
postMessage fréquents (surtout avec de gros objets) peuvent devenir un goulot d'étranglement. Préférez le batching et l'utilisation d'objets transférables quand c'est pertinent.\n- Coût mémoire : chaque worker a son propre usage mémoire et un coût de démarrage ; trop de workers peut augmenter l'utilisation RAM et la consommation de batterie.\n- Croissance du cache : un Service Worker qui met en cache de manière agressive peut gonfler le stockage. Ajoutez des limites de cache et du nettoyage pendant les mises à jour.Toutes les capacités ne sont pas disponibles partout (ou les utilisateurs peuvent bloquer des permissions). Faites de la détection de fonctionnalités et dégradez proprement :
if ('serviceWorker' in navigator) {
// enregistrer le service worker
} else {
// continuer sans fonctionnalités hors ligne
}
L'objectif : la fonctionnalité de base doit toujours marcher, avec les « plus » (hors ligne, push, calculs lourds) ajoutés quand ils sont disponibles.
Les Web Workers et les Service Workers résolvent des problèmes différents, donc ils se complètent bien quand une app a à la fois du calcul lourd et des chargements rapides/fiables. Un bon modèle mental : Web Worker = calcul, Service Worker = réseau + cache, thread principal = UI.
Supposons que votre app permet d'éditer des photos (redimensionner, filtres, suppression d'arrière-plan) et de voir une galerie plus tard sans connexion.
Cette approche « calculer puis mettre en cache » garde les responsabilités séparées : le worker produit des sorties, et le service worker décide comment les stocker et les servir.
Pour des apps avec flux, formulaires ou données de terrain :
Même sans synchronisation complète en arrière-plan, un service worker améliore la vitesse perçue en servant des réponses en cache pendant que l'app met à jour en arrière-plan.
Évitez de mélanger les rôles :
postMessage).\n- Service Worker : routage des requêtes, stratégie de cache, fallback hors ligne.Non. Un Service Worker s'exécute en arrière-plan, séparé de tout onglet de page, et il n'a pas d'accès direct au DOM (aux éléments HTML de la page).
Cette séparation est volontaire : les Service Workers sont conçus pour continuer à fonctionner même lorsqu'aucune page n'est ouverte (par exemple pour répondre à un événement push ou pour servir des fichiers mis en cache). Parce qu'il peut ne pas y avoir de document actif à manipuler, le navigateur le garde isolé.
Si un Service Worker a besoin d'affecter ce que l'utilisateur voit, il communique avec les pages via des messages (par exemple postMessage) afin que la page mette à jour l'UI.
Non. Les Web Workers et les Service Workers sont indépendants.
Vous pouvez utiliser l'un seul, l'autre, ou les deux selon les besoins de votre application.
Dans les navigateurs modernes, les Web Workers sont largement supportés et constituent généralement un choix de base sûr.
Les Service Workers sont également largement supportés dans les versions récentes des principaux navigateurs, mais ils ont plus d'exigences et de cas limites :
localhost pour le développement).\n- Certaines fonctionnalités (comme les notifications push) varient selon le navigateur et la plateforme.Si la compatibilité large est importante, considérez les Service Workers comme une amélioration progressive : construisez d'abord une bonne expérience de base, puis ajoutez le hors ligne/push là où c'est disponible.
Pas automatiquement.
Les vrais gains viennent d'utiliser le bon worker pour le bon goulot d'étranglement, et de mesurer avant/après.
Utilisez un Web Worker quand vous avez un travail lourd en CPU qui peut s'exprimer comme « entrée → calcul → sortie » et qui n'a pas besoin d'accéder au DOM.
Les cas d'usage appropriés incluent le parsing/transform d'importants payloads, la compression/décompression, la cryptographie, le traitement d'images/sons et le filtrage complexe. Si le travail consiste principalement en mises à jour de l'interface ou en lectures/écritures fréquentes du DOM, un worker n'aidera pas (et ne peut pas accéder au DOM de toute façon).
Utilisez un Service Worker lorsque vous avez besoin de contrôle réseau : prise en charge hors ligne, stratégies de cache, accélérer les visites répétées, routage des requêtes et (lorsque supporté) push / background sync.
Si votre problème est « l'interface se fige pendant un calcul », c'est un problème pour un Web Worker. Si votre problème est « le chargement est lent / hors ligne ne fonctionne pas », c'est un problème pour un Service Worker.
Non. Les Web Workers et les Service Workers sont indépendants.
Vous pouvez utiliser l'un sans l'autre, ou les combiner si votre application a à la fois des besoins de calcul et des besoins réseau/hors ligne.
Principalement la portée et la durée de vie.
fetch) même lorsqu'aucune page n'est ouverte, puis se terminer lorsqu'il est inactif.Non. Les Web Workers n'ont pas accès à window/document.
Si vous devez affecter l'interface utilisateur, renvoyez les données au thread principal via postMessage(), puis mettez à jour le DOM dans le code de la page. Gardez le worker focalisé sur du pur calcul.
Non. Les Service Workers n'ont pas accès au DOM.
Pour influencer ce que l'utilisateur voit, communiquez avec les pages contrôlées via des messages (par exemple en utilisant l'API Clients + postMessage()), et laissez la page mettre à jour l'interface.
Utilisez postMessage() des deux côtés.
worker.postMessage(data)self.postMessage(result)Pour de grandes données binaires, préférez les transferables (comme ArrayBuffer) pour éviter les copies :
Les Service Workers se placent entre votre application et le réseau et peuvent répondre aux requêtes en utilisant la Cache Storage API.
Stratégies courantes :
Choisissez une stratégie par type de ressource (app shell vs données API), pas une règle globale unique.
Oui, mais gardez les responsabilités claires.
Un schéma courant :
Cela évite de mêler la logique d'interface aux contextes d'arrière-plan et rend les performances plus prévisibles.
Utilisez la surface DevTools adaptée pour chaque cas.
onmessage, et profilez pour confirmer que le thread principal reste réactif.Lors du débogage des problèmes de cache, vérifiez toujours ce qui est réellement servi (réseau vs cache) et testez le mode hors ligne / l'émulation réseau.
worker.postMessage(buffer, [buffer]);