Get to know MDN better
Cette page a été traduite à partir de l'anglais par la communauté. Vous pouvez contribuer en rejoignant la communauté francophone sur MDN Web Docs.
Dans cet article, nous aborderons les notions pour vous permettre de démarrer avec les service workers comme l'architecture associée, l'enregistrement d'un service worker, les processus d'installation et d'activation pour un nouveau service worker, la mise à jour d'un service worker, le contrôle du cache associé et les réponses personnalisées en appliquant ceci à une application d'exemple simple ayant des fonctionnalités hors-ligne.
Un problème qui se pose depuis plusieurs années sur le Web est la perte de connexion au réseau. Une application web, si performante soit elle, fournira un service déplorable si on ne peut pas la télécharger. Plusieurs tentatives ont eu lieu pour résoudre ce problème et certains aspects ont été réglés. Toutefois, il était encore difficile de bien contrôler la mise en cache de données et de gérer l'interception de requêtes.
Les service workers aident à résoudre ces problèmes. En utilisant un service worker, on peut mettre en place une application qui utilise des fichiers en cache et ainsi fournir des fonctionnalités, même hors ligne, avant d'obtenir des données depuis le réseau. Ce qui est possible avec les applications natives devient possible avec les applications web.
Un service worker fonctionne comme un serveur intermédiaire (« proxy »), permettant de modifier les requêtes et les réponses en utilisant les éléments qu'il a en cache.
Les service workers sont présents par défaut dans les navigateurs. Pour exécuter du code dans des service workers, il faut qu'il soit servi avec HTTPS (pour des raisons de sécurité). Il est donc nécessaire d'avoir un serveur web prenant en charge HTTPS (ça peut être grâce à un service comme GitHub, Netlify, Vercel, etc.). Afin de simplifier le développement local, localhost est également considéré par les navigateurs comme une origine sécurisée.
Lors de la mise en place d'un service worker, on a généralement les étapes suivantes :
Voici les évènements disponibles pour un service worker :
Pour illustrer les bases de l'enregistrement et de l'installation d'un service worker, nous avons créé une application d'exemple intitulée simple-service-worker (angl.), qui est une galerie d'images de Lego Star Wars. Elle utilise une fonction à base de promesses pour lire les données des images depuis un objet JSON et charger les images avec fetch() avant de les afficher sur une ligne dans la page. L'exemple n'utilise que des ressources statiques. Nous verrons aussi l'enregistrement, l'installation et l'activation d'un service worker.
Vous pouvez consulter le code source sur GitHub (angl.), ainsi que le service worker simple en fonctionnement (angl.).
Le premier bloc de code du fichier JavaScript — app.js — sert de point d'entrée pour l'utilisation des service workers.
Cela permet d'enregistrer un service worker, qui s'exécute dans un contexte de worker, et n'a donc pas accès au DOM.
Un seul service worker peut contrôler de nombreuses pages. Chaque fois qu'une page concernée par la portée du service worker est chargée, le service worker est installé pour cette page et s'en occupe. Il faut donc faire attention aux variables globales dans le script d'un service worker : chaque page ne récupère pas son propre worker unique.
Note : Un avantage des service workers est que si vous utilisez la détection de fonctionnalité comme montré ci-dessus, les navigateurs qui ne prennent pas en charge les service workers peuvent simplement utiliser votre application en ligne de façon normale comme prévu.
Il peut y avoir plusieurs raisons :
Une fois le service worker enregistré, le navigateur essaiera d'installer le service worker sur la page/le site.
L'évènement install est déclenché lorsque l'installation s'est déroulée correctement. Il est généralement utilisé pour remplir les caches qui seront utilisés hors ligne. Pour cela, on utilise l'API de stockage des service worker — cache — un objet global du service worker qui permet de stocker les fichiers fournis par les réponses et de les référencées par des clés formées par les requêtes. Cette API fonctionne de façon semblable au cache standard du navigateur, mais est spécifique au domaine. Le cache persiste jusqu'à nouvel ordre.
Voici comment nous gérons l'évènement install dans notre exemple :
Note : L'API Web Storage (localStorage) fonctionne de façon semblable au cache d'un service worker mais est synchrone et son utilisation n'est donc pas autorisée dans les services workers.
Note : Si besoin, l'API IndexedDB peut être utilisée dans un service worker pour stocker des données.
Maintenant que les fichiers sont mis en cache, il faut indiquer au service worker quoi faire de ce contenu. Pour cela, on utilise l'évènement fetch.
Un évènement fetch est déclenché à chaque fois qu'une ressource doit être récupérée depuis une page contrôlée par un service worker. Cela inclut les documents situés dans la portée du worker et les ressources référencées depuis ces documents (ainsi, si index.html effectue une requête vers une origine différente pour charger une image, la requête passera quand même par le service worker).
On peut attacher un gestionnaire d'évènement pour fetch au service worker, puis appeler la méthode respondWith() sur l'évènement afin d'intercepter les réponses HTTP et les remplacer par le contenu voulu.
On peut ainsi répondre avec les ressources dont l'URL correspond à la requête interceptée :
caches.match(event.request) permet de cibler les ressources demandées sur le réseau avec les ressources équivalentes et qui sont disponibles dans le cache (si une telle ressource est disponible). La correspondance est effectuée avec l'URL et différents en-têtes, comme pour une requête HTTP normale.
caches.match(event.request) fonctionne à merveille s'il y a une ressource correspondante dans le cache du service worker, mais que se passe-t-il si ce n'est pas le cas ? Si on ne fournit pas de gestion d'erreur, la promesse est résolue avec undefined et rien ne sera renvoyé.
Dans ce cas, on peut tester la réponse du cache et, si besoin, utiliser une requête réseau classique :
Ainsi, si les ressources ne sont pas dans le cache, on les récupère depuis le réseau.
Une stratégie plus raffinée serait de mettre en cache les ressources que nous récupérons depuis le réseau afin qu'elles puissent être réutilisées hors ligne par la suite. Dans notre exemple, cela signifie que si nous ajoutons de nouvelles images à la galerie, notre application pourrait automatiquement les récupérer la première fois et les mettre en cache. Voici un fragment de code qui implémente cette méthode :
Si la ressource de la requête n'est pas disponible dans le cache, on la demande depuis le réseau avec await fetch(request). Ensuite, on clone la réponse dans le cache. La fonction putInCache() utilise caches.open('v1') et cache.put() afin d'ajouter les ressources au cache. La réponse originale est transmise au navigateur pour la page qui a demandé la ressource.
Cloner la réponse est nécessaire, car les flux de requête et de réponse ne peuvent être lus qu'une seule fois. Afin de fournir la réponse au navigateur et la mettre en cache, il faut la cloner. La version originale est fournie au navigateur et le clone est mis en cache. Chaque réponse est lue une seule fois.
Ce qui peut sembler un peu étrange, c'est que la promesse retournée par putInCache() n'est pas attendue. La raison est que nous ne voulons pas attendre que le clone de la réponse ait été ajouté au cache avant de retourner une réponse. Cependant, il est nécessaire d'appeler event.waitUntil() sur la promesse, pour s'assurer que le service worker ne se termine pas avant que le cache ne soit rempli.
Le problème restant est que si la requête ne correspond à rien en cache et que le réseau n'est pas disponible, la requête échouera. Voyons comment fournir un contenu par défaut dans ce cas-là :
Nous avons choisi cette image de secours car les seules mises à jour susceptibles d'échouer sont les nouvelles images, tout le reste dépendant de l'installation dans le gestionnaire d'évènement install vu précédemment.
S'il est activé, le préchargement à la navigation commence le téléchargement des ressources dès que la requête de récupération est émise, en parallèle de l'activation du service worker. Cela permet que le téléchargement démarre immédiatement lors de la navigation vers une page plutôt que d'avoir à d'abord attendre l'activation du service worker. Ce délai se produit rarement mais reste inévitable et, lorsqu'il survient, peut être significatif.
Pour commencer, la fonctionnalité doit être activée lors de l'activation du service worker en utilisant registration.navigationPreload.enable() :
Ensuite, on utilisera event.preloadResponse pour attendre que le téléchargement de la ressource préchargée soit terminée dans le gestionnaire d'évènement fetch.
Reprenons le code des sections précédentes et insérons la gestion du préchargement après la vérification du cache et avant la récupération depuis le réseau.
Voici l'algorithme mis à jour :
On notera dans cet exemple qu'on télécharge et met en cache les mêmes données pour la ressource qu'elle soit téléchargée normalement ou préchargée. On pourrait aussi choisir de télécharger et de mettre en cache une ressource différente lors du préchargement. Pour plus d'informations, voir NavigationPreloadManager > réponses personnalisées.
Si le service worker a précédemment été installé et qu'une nouvelle version est disponible lors du rafraîchissement ou du chargement de la page, la nouvelle version est installée en arrière-plan, mais n'est pas activée. Elle est uniquement activée lorsqu'il n'y a plus de pages chargées qui utilisent l'ancien service worker. Dès qu'il n'y a plus de page chargée, le nouveau service worker s'active.
Note : Il est possible de contourner ce comportement en utilisant Clients.claim().
Il faut alors mettre à jour le gestionnaire d'évènement pour install dans le nouveau service worker (notez le nouveau numéro de version) :
Lorsque cette installation se produit, la version précédente est toujours utilisée pour les interceptions/récupérations de ressources. La nouvelle version est installée en arrière-plan. En appelant notre nouveau cache v2, le cache v1 précédent n'est pas perturbé.
Lorsqu'aucune page n'utilise la version précédente, c'est le nouveau service worker qui est activé et qui devient alors responsable des interceptions/récupérations.
Comme nous l'avons vu dans la section précédente, lorsqu'on met à jour un service worker avec une nouvelle version, on pourra créer un nouveau cache avec le gestionnaire d'évènement install. Tant qu'il y a des pages ouvertes qui sont contrôlées par l'ancienne version, il faut conserver les deux caches, car la version précédente utilise cette version précédente du cache. L'évènement activate peut ensuite être utilisé pour retirer des données des caches précédents.
Les promesses passées à waitUntil() bloqueront les autres évènements tant qu'elles ne seront pas terminées. Cela permet de s'assurer que les étapes de nettoyage auront été réalisées lorsque le premier évènement fetch parviendra au nouveau service worker.
Cette page a été modifiée le 28 mars 2026 par les contributeur·ice·s du MDN.
Votre modèle pour un internet meilleur.
Visitez la société mère à but non lucratif de Mozilla Corporation, la Fondation Mozilla.
Certaines parties de ce contenu sont protégées par le droit d'auteur ©1998—2026 des contributeurs individuels de mozilla.org. Contenu disponible sous une licence Creative Commons.