1. Introduction
A Service Worker is a powerful feature in modern web development that enables your web applications to run in the background—even when the browser is closed—and to provide rich offline experiences, background syncing, and push notifications.
It is an essential building block of Progressive Web Apps (PWAs).
2. What is a Service Worker?
A Service Worker is a JavaScript file that:
- Runs independently of your main web page (browser thread)
- Acts like a proxy server between your web application, the browser, and the network
- Allows you to intercept and handle network requests
- Can cache responses, enabling offline access to parts (or all) of your app
- Supports background tasks like push notifications and syncing data in the background
3. Key Characteristics of a Service Worker
- Runs in the Background
- A service worker is not tied to any specific web page.
- It runs in a separate context, meaning even if your app is closed, it can still handle events like push notifications.
- Event-Driven
- Service workers don’t run all the time. They wake up to respond to events like:
install
– when the service worker is being installedactivate
– when it becomes activefetch
– when the page makes a network requestpush
– when a push notification arrivessync
– when background sync happens
- Service workers don’t run all the time. They wake up to respond to events like:
- Intercepts Network Requests
- Service workers can listen to all outgoing requests made by your app and decide:
- Whether to serve cached content
- Whether to fetch from the internet
- Whether to show a fallback message/page
- Service workers can listen to all outgoing requests made by your app and decide:
- Secure Context Only
- Service workers only work on HTTPS (or on
localhost
during development) because they can intercept network traffic and must not be vulnerable to attacks.
- Service workers only work on HTTPS (or on
- Asynchronous and Promise-Based
- All service worker APIs use Promises, which helps in managing asynchronous operations like caching, responding to fetch events, etc.
4. Why is it Useful?
Use Case | Benefit |
Offline Support | Enables web apps to work even without internet by serving cached files. |
Faster Load Times | Cached assets load instantly, making apps feel snappy and responsive. |
Push Notifications | Keeps users engaged with real-time updates even when the app is closed. |
Background Sync | Syncs data when the network becomes available, useful for forms or messages. |
Control Over Requests | Decide how requests are handled—cache-first, network-first, stale-while-revalidate, etc. |
5. How Does a Service Worker Work? (Step-by-Step)
5.1 Registration
The service worker is registered from your web page using:
navigator.serviceWorker.register('/sw.js');
This tells the browser to install and manage the /sw.js
file as a service worker.
5.2 Installation
The install
event is triggered once, the first time the service worker is registered. You usually cache static assets here using the Cache API.
5.3 Activation
After the service worker is installed, the activate
event is fired. This is where you clean up old caches or update assets if needed.
5.4 Fetching
When the user opens your site again, the service worker intercepts all network requests. It can decide to serve them from cache or fetch them from the internet.
5.5 Lifecycle Management
Service workers are automatically terminated when not in use and restarted when needed. This means they don’t consume memory when idle.
6. Minimum Requirements to Use a Service Worker
- Must be served over HTTPS
- Must be registered from the root or a subfolder
- Only modern browsers support it (but support is widespread)
7. Example Capabilities Beyond Caching
Feature | Description |
Push Notifications | Receive and display messages from the server even when the app is closed |
Background Sync | Wait until the device is online, then send queued data (e.g., form submissions) |
Periodic Background Sync | Schedule regular sync events |
Navigation Preload | Speed up page loads by allowing parallel loading and SW boot |
8. Example of Service Worker
8.1 Project Structure
/my-pwa │ ├── index.html ├── sw.js └── manifest.json ← optional for now
index.html
<!DOCTYPE html> <html> <head> <title>Simple PWA</title> </head> <body> <h1>Hello, this is a basic PWA</h1> <p>If you're offline, this page can still load.</p> <script> // Register the service worker if ('serviceWorker' in navigator) { navigator.serviceWorker.register('sw.js') .then(reg => console.log('Service Worker registered:', reg.scope)) .catch(err => console.error('Service Worker registration failed:', err)); } </script> </body> </html>
sw.js
(Service Worker)
// Service worker install event self.addEventListener('install', function(event) { console.log('[ServiceWorker] Install'); event.waitUntil( caches.open('my-cache-v1').then(function(cache) { return cache.addAll([ './index.html' ]); }) ); }); // Service worker fetch event self.addEventListener('fetch', function(event) { event.respondWith( caches.match(event.request).then(function(response) { // Return the cached response if available, otherwise fetch from network return response || fetch(event.request); }) ); });
Now run the application locally.
8.2 How to Test Offline Support
- Open your app in Chrome.
- Open DevTools → Application tab → Service Workers → Check “Offline”.
- Reload the page — it will load from the cache!
9. Understanding Code
9.1 Install Event
self.addEventListener('install', function(event) {
This tells the service worker what to do when it’s first installed in the browser.
event.waitUntil( caches.open('my-cache-v1').then(function(cache) { return cache.addAll([ './index.html' ]); }) );
event.waitUntil(...)
ensures the service worker doesn’t finish installing until the code inside completes.caches.open('my-cache-v1')
opens a named cache storage.cache.addAll([...])
adds theindex.html
file to the cache so it can be served later (even offline).
9.2 Fetch Event
self.addEventListener('fetch', function(event) {
This listens for any network request made by your web page (e.g., when loading HTML, CSS, images, etc.).
event.respondWith( caches.match(event.request).then(function(response) {
event.respondWith(...)
tells the browser to respond to the request with a custom response (our own logic).caches.match(event.request)
checks if the requested file is already in the cache.
return response || fetch(event.request);
- If the file is in the cache (
response
exists), return it. - Otherwise, fetch it from the network.