刷刷题20 (Service Worker )

217 阅读2分钟

典型场景示例

  • 新闻类应用:离线阅读已缓存文章,后台预拉取最新内容‌。
  • 电商平台:弱网下展示商品缓存页,断网时暂存用户购物车操作‌。
  • 协作工具:多设备间实时同步编辑内容,断网后自动提交未保存更改‌。

一、基本概念

Service Worker(SW)是运行在浏览器后台的独立线程,用于拦截网络请求、管理缓存资源及实现离线功能,是 PWA(渐进式 Web 应用)的核心技术。其特点包括:

  • 无法直接操作 DOM,需通过 postMessage 与主线程通信‌;
  • 必须运行在 HTTPS 或 localhost 环境‌;
  • 生命周期独立于网页,可长期存活并处理后台任务‌

二、注册 Service Worker

通过 navigator.serviceWorker.register() 注册 SW 脚本,通常建议在页面加载完成后执行:

// 主线程代码
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/sw.js', { scope: '/' })
      .then(registration => {
        console.log('SW 注册成功:', registration.scope); // ‌:ml-citation{ref="4,5" data="citationList"}
      })
      .catch(error => {
        console.log('SW 注册失败:', error);
      });
  });
}

三、安装阶段(Install Event)

SW 首次注册或更新时会触发 install 事件,通常用于缓存核心静态资源:

// SW 线程代码 (sw.js)
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open('my-cache-v1') // 创建/打开缓存空间
      .then(cache => {
        return cache.addAll([ // 缓存关键资源
          '/',
          '/styles.css',
          '/app.js'
        ]);
      })
  );
}); //:ml-citation{ref="4,6" data="citationList"}

四、激活阶段(Activate Event)

当新 SW 准备就绪时触发 activate 事件,通常用于清理旧缓存:

self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.filter(name => name !== 'my-cache-v1')
          .map(name => caches.delete(name)) // 删除旧缓存
      );
    })
  );
  self.clients.claim(); // 立即控制所有页面‌:ml-citation{ref="5,7" data="citationList"}
});

五、拦截请求(Fetch Event)

SW 通过 fetch 事件拦截网络请求,实现缓存优先或网络优先策略:

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request) // 检查缓存
      .then(response => {
        return response || fetch(event.request) // 返回缓存或发起网络请求
          .then(res => {
            return caches.open('my-cache-v1') // 动态缓存新资源
              .then(cache => {
                cache.put(event.request, res.clone());
                return res;
              });
          });
      })
  ); // ‌:ml-citation{ref="1,5" data="citationList"}
});

六、通信机制

SW 与主线程通过 postMessage 和 message 事件通信:

// 主线程发送消息
navigator.serviceWorker.controller.postMessage({ type: 'UPDATE_DATA' });

// SW 监听消息
self.addEventListener('message', event => {
  if (event.data.type === 'UPDATE_DATA') {
    // 处理逻辑并回复
    event.source.postMessage({ status: 'Updated' }); // ‌:ml-citation{ref="2,5" data="citationList"}
  }
});

七、生命周期注意事项

  • 更新机制:SW 脚本内容变化时会触发更新,需通过 skipWaiting() 强制激活新版本‌;
  • 调试工具:Chrome DevTools 的 Application > Service Workers 面板可查看状态及模拟离线环境‌。