Handling Unreliable Connectivity with Chrome Service Workers
Stop letting 'Lie-Fi' ruin your user experience. Learn how to use Chrome Service Workers to implement caching strategies and background sync for a truly offline-first web app.
11 Jul 2025, 09:52 UTC

The 'Lie-Fi' Problem
\nWe have all experienced \"Lie-Fi\": the state where your device shows a full signal bar, but the page refuses to load because the connection is stalled or extremely slow. For a user, this is more frustrating than being completely offline, as the browser continues to attempt network requests that will eventually time out, leaving the user staring at a blank loading screen.
\nThe solution is to move the network logic out of the main browser thread and into a Service Worker. A Service Worker is a script that the browser runs in the background, separate from a web page, enabling features that don't need a web page or user interaction to work. By intercepting network requests, you can decide instantly whether to serve a cached version of a page or wait for the network.
\n\nImplementing a Caching Strategy
\nThe core of a Service Worker is the fetch event listener. This allows you to implement different strategies based on the type of data you are requesting. A common approach for assets like CSS and JS is Cache-First, while dynamic data often uses Stale-While-Revalidate.
- \n
- Cache-First: Check the cache; if found, return it immediately. If not, fetch from the network and cache the result for next time. \n
- Network-First: Attempt the network request first. If it fails (offline), fall back to the cache. \n
- Stale-While-Revalidate: Serve the cached version immediately for speed, but fetch an update in the background to update the cache for the next visit. \n
Example: A Basic Offline-Ready Worker
\nTo implement this, you first register the worker in your main JavaScript file. This must be done in a secure context (HTTPS or localhost).
\n// main.js\nif ('serviceWorker' in navigator) {\n window.addEventListener('load', () => {\n navigator.serviceWorker.register('/sw.js')\n .then(reg => console.log('SW registered!', reg))\n .catch(err => console.error('SW registration failed:', err));\n });\n}\nThen, create the sw.js file to handle the caching logic. In this example, we use a Cache-First strategy for specific assets:
// sw.js\nconst CACHE_NAME = 'site-static-v1';\nconst ASSETS = ['/', '/styles.css', '/script.js', '/offline.html'];\n\n// Install event: Pre-cache essential assets\nself.addEventListener('install', (event) => {\n event.waitUntil(\n caches.open(CACHE_NAME).then((cache) => cache.addAll(ASSETS))\n );\n});\n\n// Fetch event: Intercept requests\nself.addEventListener('fetch', (event) => {\n event.respondWith(\n caches.match(event.request).then((cachedResponse) => {\n // Return cached asset or fetch from network\n return cachedResponse || fetch(event.request).catch(() => {\n // Fallback to offline page if network fails and not in cache\n return caches.match('/offline.html');\n });\n })\n );\n});\n\nDeferred Actions with Background Sync
\nCaching handles reading data, but Background Sync handles writing it. If a user submits a form while their connection is flickering, a standard request would simply fail. Background Sync allows the Service Worker to defer that request until the browser detects a stable connection.
\nWhen the user clicks \"Submit,\" the application registers a sync tag. The browser then wakes up the Service Worker once connectivity is restored to execute the upload, even if the user has closed the tab.
\n\nConstraints and Trade-offs
\nService Workers are powerful, but they introduce a specific set of risks:
\n- \n
- Cache Staleness: If you use a Cache-First strategy, users may not see updates to your site until the Service Worker is updated and the old cache is deleted. You must implement a versioning system for your
CACHE_NAME. \n - Storage Quotas: Chrome imposes storage limits per origin. While usually generous, very large caches can be evicted automatically if the device runs low on disk space. \n
- Lifecycle Complexity: A new Service Worker doesn't take control of a page immediately; it stays in a \"waiting\" state until all tabs using the old worker are closed. \n
Verification and Debugging
\nTo verify your implementation in Chrome:
\n- \n
- Open DevTools (F12) → Application tab. \n
- Select Service Workers in the left sidebar to see if the worker is \"Activated and running.\" \n
- Check the Cache Storage section to ensure your
ASSETSarray was successfully cached. \n - Check the Network tab and toggle the Offline checkbox to test if your
/offline.htmlfallback triggers correctly. \n
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.