Browser APIs
Service Workers
Enable offline experiences and background sync
Advanced
browser pwa offline caching
Definition
Service Workers are scripts that run in the background, separate from the web page, enabling features like push notifications, background sync, and offline experiences. They act as a programmable network proxy, allowing you to control how network requests from your page are handled.
Lifecycle
Registration
// main.js
if ('serviceWorker' in navigator) {
window.addEventListener('load', async () => {
try {
const registration = await navigator.serviceWorker.register('/sw.js');
console.log('SW registered:', registration.scope);
// Check for updates
registration.addEventListener('updatefound', () => {
const newWorker = registration.installing;
console.log('New SW installing:', newWorker);
});
} catch (error) {
console.error('SW registration failed:', error);
}
});
}
Service Worker Script
// sw.js
const CACHE_NAME = 'v1';
const urlsToCache = [
'/',
'/styles.css',
'/app.js',
'/icon.png'
];
// Install event - cache assets
self.addEventListener('install', (event) => {
console.log('Service Worker installing');
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(urlsToCache))
.then(() => self.skipWaiting())
);
});
// Activate event - clean old caches
self.addEventListener('activate', (event) => {
console.log('Service Worker activating');
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames
.filter(name => name !== CACHE_NAME)
.map(name => caches.delete(name))
);
}).then(() => self.clients.claim())
);
});
// Fetch event - serve from cache or network
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then(response => {
// Return cached version or fetch from network
if (response) {
return response;
}
return fetch(event.request);
})
);
});
Caching Strategies
Cache First
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then(response => {
return response || fetch(event.request);
})
);
});
Network First
self.addEventListener('fetch', (event) => {
event.respondWith(
fetch(event.request)
.catch(() => caches.match(event.request))
);
});
Stale While Revalidate
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.open(CACHE_NAME).then(cache => {
return cache.match(event.request).then(response => {
const fetchPromise = fetch(event.request).then(networkResponse => {
cache.put(event.request, networkResponse.clone());
return networkResponse;
});
return response || fetchPromise;
});
})
);
});
Advanced Features
Background Sync
// In main.js
navigator.serviceWorker.ready.then(registration => {
return registration.sync.register('sync-data');
});
// In sw.js
self.addEventListener('sync', (event) => {
if (event.tag === 'sync-data') {
event.waitUntil(syncDataWithServer());
}
});
async function syncDataWithServer() {
const data = await getPendingData();
await fetch('/api/sync', {
method: 'POST',
body: JSON.stringify(data)
});
}
Push Notifications
// In sw.js
self.addEventListener('push', (event) => {
const data = event.data.json();
event.waitUntil(
self.registration.showNotification(data.title, {
body: data.body,
icon: '/icon.png',
badge: '/badge.png',
data: data.url
})
);
});
self.addEventListener('notificationclick', (event) => {
event.notification.close();
event.waitUntil(
clients.openWindow(event.notification.data)
);
});
Best Practices
// Version your cache
const CACHE_NAME = 'my-app-v2';
// Precache critical resources
const PRECACHE_ASSETS = [
'/',
'/offline.html',
'/styles.css',
'/app.js'
];
// Implement cache cleanup
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames
.filter(name => !name.startsWith('my-app'))
.map(name => caches.delete(name))
);
})
);
});
Key Takeaway
Service Workers enable offline functionality, background sync, and push notifications. They follow a specific lifecycle (installing, waiting, activating) and intercept network requests to serve cached content. Use versioning for cache management and implement appropriate caching strategies for different resource types.