概述Service Worker 为前端提供离线缓存与网络请求控制能力。本文给出可落地的策略实现,并结合 IndexedDB 进行数据同步与重试。注册与预缓存if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js'); } `sw.js` 中预缓存静态资源:const PRECACHE = 'precache-v1'; const PRECACHE_URLS = ['/index.html', '/styles.css', '/app.js']; self.addEventListener('install', event => { event.waitUntil( caches.open(PRECACHE).then(cache => cache.addAll(PRECACHE_URLS)) ); }); self.addEventListener('activate', event => { event.waitUntil( caches.keys().then(keys => Promise.all(keys.filter(k => k !== PRECACHE).map(k => caches.delete(k)))) ); }); 常用缓存策略Cache First:async function cacheFirst(event) { const cache = await caches.open('cf-v1'); const cached = await cache.match(event.request); if (cached) return cached; const res = await fetch(event.request); cache.put(event.request, res.clone()); return res; } Network First:async function networkFirst(event) { const cache = await caches.open('nf-v1'); try { const res = await fetch(event.request); cache.put(event.request, res.clone()); return res; } catch { const cached = await cache.match(event.request); if (cached) return cached; return new Response('', { status: 503 }); } } Stale While Revalidate:async function staleWhileRevalidate(event) { const cache = await caches.open('swr-v1'); const cached = await cache.match(event.request); const networkPromise = fetch(event.request).then(res => { cache.put(event.request, res.clone()); return res; }); return cached ? cached : networkPromise; } 路由分发:self.addEventListener('fetch', event => { const url = new URL(event.request.url); if (url.pathname.startsWith('/api/')) { event.respondWith(networkFirst(event)); } else if (event.request.destination === 'image') { event.respondWith(cacheFirst(event)); } else { event.respondWith(staleWhileRevalidate(event)); } }); 离线数据同步与重试将失败的写请求持久化到 IndexedDB,并在下次网络恢复时重试。function openDB(name) { return new Promise((resolve, reject) => { const req = indexedDB.open(name, 1); req.onupgradeneeded = () => { const db = req.result; if (!db.objectStoreNames.contains('queue')) { db.createObjectStore('queue', { autoIncrement: true }); } }; req.onsuccess = () => resolve(req.result); req.onerror = () => reject(req.error); }); } async function enqueue(req) { const db = await openDB('sync'); const tx = db.transaction('queue', 'readwrite'); tx.objectStore('queue').add(req); await new Promise((resolve, reject) => { tx.oncomplete = resolve; tx.onerror = () => reject(tx.error); }); db.close(); } self.addEventListener('fetch', event => { if (event.request.method === 'POST') { event.respondWith( fetch(event.request).catch(async () => { const body = await event.request.clone().text(); await enqueue({ url: event.request.url, body }); return new Response('', { status: 202 }); }) ); } }); self.addEventListener('sync', event => { if (event.tag === 'retry-queue') { event.waitUntil( openDB('sync').then(async db => { const tx = db.transaction('queue', 'readwrite'); const store = tx.objectStore('queue'); const all = []; const req = store.openCursor(); await new Promise((resolve, reject) => { req.onsuccess = e => { const cursor = e.target.result; if (cursor) { all.push({ key: cursor.key, value: cursor.value }); cursor.continue(); } else resolve(); }; req.onerror = () => reject(req.error); }); for (const item of all) { try { await fetch(item.value.url, { method: 'POST', body: item.value.body }); store.delete(item.key); } catch {} } await new Promise((resolve, reject) => { tx.oncomplete = resolve; tx.onerror = () => reject(tx.error); }); db.close(); }) ); } }); 在页面端注册后台同步:navigator.serviceWorker.ready.then(reg => { if ('sync' in reg) reg.sync.register('retry-queue'); });

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部
1.925530s