乐闻世界logo
搜索文章和话题

How does Service Worker update mechanism work?

3月7日 12:06

Service Worker Update Mechanism Explained

The Service Worker update mechanism is one of its important features, and understanding it is crucial for maintaining application stability and user experience.

Update Trigger Conditions

When the browser detects changes in the Service Worker file (byte difference), it triggers the update process.

javascript
// Browser automatically checks for updates // The following situations trigger checks: // 1. When user visits the page // 2. When calling registration.update() // 3. When page refreshes (under certain conditions)

Update Lifecycle

1. Detect Update

javascript
// Manually trigger update check navigator.serviceWorker.register('/sw.js').then(registration => { // Check for updates registration.update(); // Listen for update discovery registration.addEventListener('updatefound', () => { const newWorker = registration.installing; console.log('New Service Worker version found'); }); });

2. New Version Installation

javascript
// sw.js const CACHE_NAME = 'app-v2'; // Update cache version self.addEventListener('install', event => { event.waitUntil( caches.open(CACHE_NAME).then(cache => { return cache.addAll([ '/', '/index.html', '/app.js', '/styles.css' ]); }) ); // Activate immediately, skip waiting phase self.skipWaiting(); });

3. Waiting Phase

By default, the new Service Worker version enters a waiting state until all pages controlled by the old version are closed.

javascript
// Main thread listens for state changes navigator.serviceWorker.register('/sw.js').then(registration => { registration.addEventListener('updatefound', () => { const newWorker = registration.installing; newWorker.addEventListener('statechange', () => { switch (newWorker.state) { case 'installed': if (navigator.serviceWorker.controller) { // New version waiting for activation console.log('New version installed, waiting for activation'); showUpdateNotification(newWorker); } break; case 'activated': console.log('New version activated'); break; } }); }); });

4. Activation Phase

javascript
// sw.js self.addEventListener('activate', event => { event.waitUntil( // Clean up old caches caches.keys().then(cacheNames => { return Promise.all( cacheNames .filter(name => name !== CACHE_NAME) .map(name => { console.log('Deleting old cache:', name); return caches.delete(name); }) ); }) ); // Take control of all pages immediately self.clients.claim(); });

User Notification for Updates

Option 1: Immediate Update (Recommended for Development)

javascript
// Main thread let newWorker = null; navigator.serviceWorker.register('/sw.js').then(registration => { registration.addEventListener('updatefound', () => { newWorker = registration.installing; newWorker.addEventListener('statechange', () => { if (newWorker.state === 'installed' && navigator.serviceWorker.controller) { // Show update notification showUpdateBar(); } }); }); }); // User clicks update button function applyUpdate() { if (newWorker) { newWorker.postMessage({ action: 'skipWaiting' }); } } // Listen in sw.js self.addEventListener('message', event => { if (event.data.action === 'skipWaiting') { self.skipWaiting(); } });

Option 2: Graceful Update (Recommended for Production)

javascript
// Listen for controller changes navigator.serviceWorker.addEventListener('controllerchange', () => { // Service Worker has switched, suggest user refresh page window.location.reload(); });

Option 3: Periodic Automatic Update

javascript
// Check for updates every 60 minutes setInterval(() => { navigator.serviceWorker.ready.then(registration => { registration.update(); }); }, 60 * 60 * 1000);

Update Notification UI Example

javascript
function showUpdateBar() { const updateBar = document.createElement('div'); updateBar.className = 'update-bar'; updateBar.innerHTML = ` <span>New version found, update now?</span> <button id="update-btn">Update Now</button> <button id="dismiss-btn">Later</button> `; document.body.appendChild(updateBar); document.getElementById('update-btn').addEventListener('click', () => { applyUpdate(); updateBar.remove(); }); document.getElementById('dismiss-btn').addEventListener('click', () => { updateBar.remove(); }); }

Best Practices

1. Version Control

javascript
// Use version numbers for cache management const CACHE_VERSION = 'v2.1.0'; const CACHE_NAME = `app-cache-${CACHE_VERSION}`;

2. Incremental Updates

javascript
// Only update changed resources const urlsToCache = [ '/', '/index.html?v=2', // Add version number '/app.js?v=2.1', '/styles.css?v=2.1' ];

3. Update Strategy Selection

StrategyUse CaseUser Experience
ImmediateDevelopment, urgent fixesForce refresh
GracefulProductionUser controlled
SilentNon-critical updatesUnnoticeable

4. Avoid Update Pitfalls

javascript
// ❌ Wrong: Cache Service Worker itself // Service Worker file should not be cached // ✅ Correct: Ensure Service Worker file is not cached // Set in server configuration: // Cache-Control: no-cache, no-store, must-revalidate

Debugging Tips

javascript
// View current Service Worker status navigator.serviceWorker.ready.then(registration => { console.log('Active:', registration.active); console.log('Installing:', registration.installing); console.log('Waiting:', registration.waiting); }); // Force update navigator.serviceWorker.getRegistration().then(reg => { reg.update(); }); // Unregister Service Worker navigator.serviceWorker.getRegistration().then(reg => { reg.unregister(); });

Summary

  1. Auto Detection: Browser automatically detects Service Worker file changes
  2. Install Wait: New version enters waiting state after installation by default
  3. Activate Takeover: New version activates after old pages close
  4. Cache Cleanup: Clean old version caches during activate phase
  5. User Notification: Provide friendly update notification mechanism
标签:Service Worker