JavaScript Service Worker实战

JavaScript Service Worker实战
最新回答
余盼兮

2020-11-20 17:11:13

Service Worker 是实现 Web 应用离线访问、资源缓存和后台任务的核心技术,通过拦截网络请求、管理缓存和版本更新机制,可显著提升用户体验。以下是其核心实战用法

  • 注册与激活在主 JavaScript 或 HTML 中检查浏览器支持性并注册 sw.js,通常在页面加载完成后执行:

    if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/sw.js') .then(registration => console.log('SW 注册成功,作用域:', registration.scope)) .catch(error => console.log('SW 注册失败:', error)); });}

    关键点

    sw.js 需位于有效作用域路径(如根目录或子目录)。

    注册成功后,Service Worker 进入 installing 状态,完成后进入 waiting 阶段,等待激活。

  • 缓存静态资源在 sw.js 中监听 install 和 activate 事件,实现资源预加载和旧缓存清理:

    const CACHE_NAME = 'my-site-v1';const urlsToCache = ['/', '/styles/main.css', '/scripts/app.js', '/images/logo.png'];self.addEventListener('install', event => { event.waitUntil( caches.open(CACHE_NAME).then(cache => cache.addAll(urlsToCache)) );});self.addEventListener('activate', event => { event.waitUntil( caches.keys().then(keys => Promise.all( keys.filter(key => key !== CACHE_NAME).map(key => caches.delete(key)) ) ) );});

    关键点

    install 阶段通过 caches.open 创建缓存空间,并用 cache.addAll 预加载关键资源。

    activate 阶段清理非当前版本的缓存,避免存储占用。

  • 拦截请求与缓存策略通过监听 fetch 事件,实现“优先返回缓存,失败则网络请求并缓存”的策略:

    self.addEventListener('fetch', event => { event.respondWith( caches.match(event.request).then(cachedResponse => { if (cachedResponse) return cachedResponse; return fetch(event.request).then(response => { if (!response || response.status !== 200 || !isSameOrigin(event.request)) { return response; } const responseToCache = response.clone(); caches.open(CACHE_NAME).then(cache => cache.put(event.request, responseToCache)); return response; }); }) );});function isSameOrigin(request) { const url = new URL(request.url); return url.origin === self.location.origin;}

    关键点

    caches.match 检查缓存是否存在,存在则直接返回。

    网络请求成功后,通过 response.clone() 克隆响应流(因响应流为一次性),并存入缓存。

    仅缓存状态码为 200 的同源请求,避免缓存错误或跨域资源。

  • 缓存版本更新与热更新修改 CACHE_NAME(如 my-site-v2)触发新版本安装,结合 skipWaiting 和 clients.claim 加速生效:

    self.addEventListener('install', event => { event.waitUntil( caches.open(CACHE_NAME).then(cache => cache.addAll(urlsToCache)) ); self.skipWaiting(); // 跳过 waiting 状态,立即激活});self.addEventListener('activate', event => { event.waitUntil( caches.keys().then(keys => Promise.all(keys.map(key => key !== CACHE_NAME ? caches.delete(key) : null)) ) ); self.clients.claim(); // 激活后立即控制所有客户端});

    关键点

    新版本安装后默认进入 waiting 状态,需关闭所有旧页面才会激活。

    skipWaiting() 和 clients.claim() 强制新版本立即生效,适合频繁迭代的应用。

  • 调试与注意事项

    调试工具:使用 Chrome DevTools 的 Application 面板查看缓存状态和 Service Worker 生命周期。

    路径问题:确保 sw.js 和缓存资源的路径正确,避免因作用域不匹配导致注册失败。

    缓存策略设计:根据业务需求选择“缓存优先”“网络优先”或“混合策略”,避免过度缓存或缓存失效。

    跨域处理:仅缓存同域资源,跨域请求需服务器配置 CORS 头。

    版本控制:每次更新应用时修改 CACHE_NAME,避免新旧缓存冲突。

总结:Service Worker 通过注册、缓存静态资源、拦截请求和版本更新机制,可实现离线访问和性能优化。合理设计缓存策略、处理版本更新和调试细节,能充分发挥其优势,为 PWA(渐进式 Web 应用)奠定基础。