Service Worker Offline Access Implementation
Offline access is one of the core features of Service Worker, allowing web applications to work normally without network connectivity.
Core Principle
Service Worker acts as a network proxy, intercepting all HTTP requests and deciding whether to return from cache or request from network based on caching strategies.
Implementation Steps
1. Register Service Worker
javascript// main.js if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/sw.js') .then(registration => { console.log('SW registered:', registration.scope); }) .catch(error => { console.log('SW registration failed:', error); }); }); }
2. Precache Core Resources
javascript// sw.js const CACHE_NAME = 'offline-cache-v1'; const urlsToCache = [ '/', '/index.html', '/styles.css', '/app.js', '/icons/icon-192x192.png', '/offline.html' // Offline fallback page ]; self.addEventListener('install', event => { event.waitUntil( caches.open(CACHE_NAME) .then(cache => { console.log('Cache opened'); return cache.addAll(urlsToCache); }) .catch(err => console.error('Cache failed:', err)) ); self.skipWaiting(); });
3. Intercept Requests and Return Cache
javascriptself.addEventListener('fetch', event => { event.respondWith( caches.match(event.request) .then(response => { // Cache hit, return directly if (response) { return response; } // Cache miss, request from network return fetch(event.request) .then(networkResponse => { // Dynamically cache new resources if (!networkResponse || networkResponse.status !== 200) { return networkResponse; } const responseToCache = networkResponse.clone(); caches.open(CACHE_NAME).then(cache => { cache.put(event.request, responseToCache); }); return networkResponse; }) .catch(() => { // Network failed, return offline page if (event.request.mode === 'navigate') { return caches.match('/offline.html'); } }); }) ); });
4. Clean Old Caches
javascriptself.addEventListener('activate', event => { event.waitUntil( caches.keys().then(cacheNames => { return Promise.all( cacheNames .filter(name => name !== CACHE_NAME) .map(name => caches.delete(name)) ); }) ); self.clients.claim(); });
Offline Page Design
html<!-- offline.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Offline Mode</title> <style> body { display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; font-family: Arial, sans-serif; background: #f5f5f5; } .offline-container { text-align: center; padding: 40px; } .offline-icon { font-size: 64px; margin-bottom: 20px; } h1 { color: #333; } p { color: #666; } button { padding: 10px 20px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; } </style> </head> <body> <div class="offline-container"> <div class="offline-icon">📡</div> <h1>You are currently offline</h1> <p>Please check your network connection and try again</p> <button onclick="location.reload()">Reload</button> </div> </body> </html>
Advanced Offline Strategies
1. Network First + Cache Fallback
javascriptself.addEventListener('fetch', event => { event.respondWith( fetch(event.request) .then(response => { // Update cache const clone = response.clone(); caches.open(CACHE_NAME).then(cache => { cache.put(event.request, clone); }); return response; }) .catch(() => caches.match(event.request)) ); });
2. Cache First + Background Update
javascriptself.addEventListener('fetch', event => { event.respondWith( caches.match(event.request).then(response => { const fetchPromise = fetch(event.request).then(networkResponse => { caches.open(CACHE_NAME).then(cache => { cache.put(event.request, networkResponse.clone()); }); return networkResponse; }); return response || fetchPromise; }) ); });
Network Status Detection
javascript// Detect in main thread window.addEventListener('online', () => { console.log('Network connected'); }); window.addEventListener('offline', () => { console.log('Network disconnected'); }); // Check current status if (navigator.onLine) { console.log('Online'); } else { console.log('Offline'); }
Best Practices
- Core Resources First: Ensure HTML, CSS, JS and other core resources are cached
- Graceful Degradation: Provide friendly offline page when network fails
- Cache Updates: Regularly update cache to prevent users from seeing old versions
- Cache Cleanup: Clean expired caches to avoid storage overflow
- Testing: Use Chrome DevTools Network panel to simulate offline environment