Stale‑while‑revalidate versus Network‑first for Zero‑Downtime PWA Updates in Opera on Unreliable Networks
0 reputation · 20 Jan 2024, 22:03 UTC
0 reputation · 20 Jan 2024, 22:03 UTC
Goal: Deploy a new version of a small progressive web app in Opera without causing downtime while keeping the user experience acceptable when the device frequently switches between online and offline or experiences low bandwidth.
Constraint: Both stale‑while‑revalidate and network‑first caching strategies are supported in Opera 60+ via the standard Service Worker API. Stale‑while‑revalidate serves the cached copy immediately and updates in the background, offering instant perceived performance but risking briefly outdated data after a deploy. Network‑first always tries the network first, guaranteeing the latest version when online but can introduce noticeable latency or blank screens when the connection is poor or unavailable.
Uncertainty: It is unclear which approach better balances the need for immediate availability with data freshness under spotty connectivity, and what cache‑versioning safeguards are required to prevent permanently stale assets when using stale‑while‑revalidate.
Which strategy yields lower perceived latency during an update on unreliable networks? How does each approach affect the freshness of displayed content when the device intermittently loses connectivity? What cache‑versioning practices mitigate the risk of serving permanently stale assets with stale‑while‑revalidate?
29775 reputation · 21 Jan 2024, 08:59 UTC
For a PWA that must stay usable while the device flips between online/offline or suffers low bandwidth, stale‑while‑revalidate gives lower perceived latency during an update because it serves the cached copy instantly and fetches the new version in the background. Network‑first can block the UI while waiting for a network response, leading to blank screens or noticeable delays.
v2026-10-11) in the service‑worker script name or as a constant (const CACHE_VERSION = 'v2026-10-11';)./app.js?v=2026-10-11). When the version changes, the URLs are new, forcing fresh caches.install event, pre‑cache the new assets using the versioned URLs.activate event, loop through caches.keys() and delete any cache whose name does not match the current CACHE_VERSION.max‑stale header or use Cache-Control: max-age=0, stale‑while‑revalidate=86400 to bound how long a stale response may be served.// sw.js
const CACHE_VERSION = 'v2026-10-11';
const STATIC_CACHE = `static-${CACHE_VERSION}`;
const API_CACHE = 'api-data';
self.addEventListener('install', e => {
e.waitUntil(
caches.open(STATIC_CACHE).then(cache => cache.addAll([
'/',
'/index.html',
'/styles.css?v=' + CACHE_VERSION,
'/app.js?v=' + CACHE_VERSION,
'/icon-192.png'
]))
);
});
self.addEventListener('activate', e => {
e.waitUntil(
caches.keys().then(keys => Promise.all(
keys.filter(key => !key.startsWith('static-') && key !== API_CACHE)
.map(key => caches.delete(key))
))
);
});
self.addEventListener('fetch', e => {
const url = new URL(e.request.url);
// Static assets: stale‑while‑revalidate
if (url.origin === location.origin && url.pathname.startsWith('/')) {
e.respondWith(
caches.match(e.request).then(cachedResp => {
const fetchPromise = fetch(e.request).then(networkResp => {
caches.open(STATIC_CACHE).then(cache => cache.put(e.request, networkResp.clone()));
return networkResp;
});
return cachedResp || fetchPromise;
})
);
return;
}
// API calls: network‑first with cache fallback
if (url.pathname.startsWith('/api/')) {
e.respondWith(
fetch(e.request).then(networkResp => {
caches.open(API_CACHE).then(cache => cache.put(e.request, networkResp.clone()));
return networkResp;
}).catch(() => caches.match(e.request))
);
return;
}
});
The recommendation above assumes that a short period of stale API data is acceptable. If your application requires near‑real‑time data (e.g., live chat or stock quotes), please confirm the maximum tolerable staleness for API responses; if it is effectively zero, a pure network‑first approach (with appropriate offline fallback) would be required instead of the hybrid strategy.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.