What is Service Worker?
A Service Worker is a type of web worker that essentially acts as a programmable proxy between a web page and the network. It lives in the browser, separate from the main JavaScript thread, allowing it to intercept network requests, cache resources, and provide advanced offline capabilities, push notifications, and background synchronization.
What is a Service Worker?
Service Workers are a core component of Progressive Web Apps (PWAs) and provide a powerful tool for web developers to control the network experience. Unlike traditional JavaScript, Service Workers run in the background, independent of the user interface, enabling features that previously required native applications.
Key Features and Capabilities
- Offline Caching: Intercept requests and serve cached content, allowing web apps to work offline or on unreliable networks.
- Network Proxy: Programmatically intercept and modify network requests and responses.
- Push Notifications: Engage users with re-engageable push messages, even when the browser is closed.
- Background Sync: Defer actions until the user has a stable connection.
- Asset Pre-caching: Proactively cache critical resources for faster loading.
- Performance Improvement: Implement custom caching strategies (e.g., cache-first, network-first) to optimize load times.
Service Worker Lifecycle
- Registration: The browser registers the Service Worker script.
- Installation: The Service Worker downloads, parses, and executes the script. The
installevent is fired, where resources are typically pre-cached. - Activation: After successful installation, the
activateevent is fired. This is where old caches can be cleaned up. - Idle/Termination: Service Workers are terminated when not in use to save memory, and restarted when needed.
- Update: When a new version of the Service Worker script is detected, it's installed in the background, and activated when all tabs using the old version are closed or navigate away.
Basic Implementation Example
First, register the Service Worker in your main application JavaScript. Then, within the Service Worker script itself, you handle events like install and fetch.
Registering the Service Worker (app.js)
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('ServiceWorker registered with scope:', registration.scope);
})
.catch(error => {
console.error('ServiceWorker registration failed:', error);
});
});
}
Service Worker Script (sw.js)
const CACHE_NAME = 'my-app-cache-v1';
const urlsToCache = [
'/',
'/index.html',
'/styles.css',
'/app.js'
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => {
console.log('Opened cache');
return cache.addAll(urlsToCache);
})
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
if (response) {
return response; // Found in cache
}
return fetch(event.request); // Not found, go to network
})
);
});
self.addEventListener('activate', event => {
const cacheWhitelist = [CACHE_NAME];
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheWhitelist.indexOf(cacheName) === -1) {
return caches.delete(cacheName); // Delete old caches
}
})
);
})
);
});
Considerations and Limitations
- HTTPS Requirement: Service Workers require a secure context (HTTPS) for security reasons, except when running on
localhost. - No DOM Access: They run on a separate thread and cannot directly access the DOM. Communication with the main thread is done via
postMessage. - Lifespan: Service Workers can be terminated by the browser when not in use to save resources, but will restart when an event occurs.
- Debugging: Debugging can be more complex, typically done via browser developer tools (e.g., Chrome DevTools' 'Application' tab).