Service Worker 和 Workbox 分别是什么?它们有什么区别?

20 阅读5分钟

1. Service Worker 是什么?(补充具体代码例子)

Service Worker(简称 SW)是浏览器原生提供的一个 JavaScript API,本质上是运行在后台的代理脚本(proxy server)。它像一个“中间人”,坐在网页、浏览器缓存和真实网络之间。主要职责:

  • 拦截所有网络请求(fetch 事件)
  • 决定怎么响应:直接从缓存返回、去网络取、组合两者、甚至伪造响应
  • 管理缓存(Cache Storage API)
  • 实现离线支持、推送通知、后台同步等 PWA 高级能力

它解决了什么核心问题?

  • 传统网页一断网就彻底崩(白屏、无法交互)
  • 加载慢、重复请求多(尤其静态资源)
  • 无法像原生 App 一样推送消息或在后台完成未发出的请求
  • 弱网/无网场景下用户体验差 → 流失高

一句话:Service Worker 是 PWA “可靠 + 快速 + 可安装”三大支柱中最核心的引擎,没有它就没有真正的离线 PWA。

但原生写法很底层:生命周期(install → activate)、缓存管理、策略实现、边缘 case(范围请求、opaque 响应、跨域等)都需要自己手写,容易出错、代码量大、维护难。

原生 Service Worker 基本示例(一个简单的预缓存 + Cache First 策略,适合学习理解底层):

// sw.js(放在项目根目录)
const CACHE_NAME = 'my-pwa-cache-v1';
const urlsToCache = [
  '/',                    // 首页
  '/index.html',
  '/styles/main.css',
  '/scripts/app.js',
  '/images/logo.png'
];

// 安装阶段:预缓存核心资源
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache => {
        console.log('Opened cache');
        return cache.addAll(urlsToCache);
      })
      .catch(err => console.error('Precache failed:', err))
  );
  // 跳过等待,直接激活(常见优化)
  self.skipWaiting();
});

// 激活阶段:清理旧缓存
self.addEventListener('activate', event => {
  const cacheWhitelist = [CACHE_NAME];
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.map(cacheName => {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
  // 立即接管所有客户端页面
  self.clients.claim();
});

// 拦截请求:简单的 Cache First 策略
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(cachedResponse => {
        // 缓存命中,直接返回
        if (cachedResponse) {
          return cachedResponse;
        }

        // 否则走网络,并尝试缓存响应(只缓存成功的 GET 请求)
        return fetch(event.request).then(networkResponse => {
          if (!networkResponse || networkResponse.status !== 200 || networkResponse.type !== 'basic') {
            return networkResponse;
          }

          // 克隆响应(因为响应流只能消费一次)
          const responseToCache = networkResponse.clone();

          caches.open(CACHE_NAME)
            .then(cache => {
              cache.put(event.request, responseToCache);
            });

          return networkResponse;
        }).catch(() => {
          // 网络失败,返回离线兜底页面(可选)
          return caches.match('/offline.html');
        });
      })
  );
});

注册方式(在主 JS 文件中):

if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/sw.js')
      .then(reg => console.log('SW registered', reg))
      .catch(err => console.error('SW registration failed', err));
  });
}

这个例子展示了原生 SW 的完整生命周期和基本缓存逻辑,但你会发现:策略一复杂起来,代码就爆炸了。

2. Workbox 是什么?(补充具体代码例子)

Workbox 是 Google 官方开源的一套 JavaScript 库(多个模块组成),专门为 Service Worker 设计的“生产级工具包”。它不取代 Service Worker,而是站在 Service Worker 的肩膀上,提供更高层的抽象和最佳实践封装。

核心模块包括:

  • 预缓存(precaching)自动生成清单
  • 路由 + 策略(routing + 5大策略:CacheFirst、NetworkFirst、StaleWhileRevalidate 等)
  • 过期管理、数量限制、广播更新
  • 后台同步、缓存清理等插件

它解决了什么问题?(针对原生 SW 的痛点)

痛点(原生 Service Worker)Workbox 如何解决实际收益(2026 年生产视角)
写 fetch 事件逻辑很繁琐、容易漏边缘 case内置策略类 + 插件系统,几行配置就实现复杂缓存代码量减少 70%+,bug 少很多
缓存过期、版本冲突、手动清理旧缓存难搞ExpirationPlugin、Cleanup 等插件自动处理缓存不会无限膨胀,版本更新更可靠
预缓存构建产物需要自己维护清单vite-plugin-pwa / workbox-webpack-plugin 自动生成 __WB_MANIFEST构建一次,清单自动更新
策略选择和组合麻烦(尤其是混合使用)runtimeCaching 配置数组,按 URL/类型一目了然匹配策略生产级策略组合 10 分钟搞定
调试难、没有好用的开发体验dev 模式自动注入、广播更新、Lighthouse 友好开发和调试效率翻倍
重复造轮子(每个人都写类似缓存逻辑)内置最佳实践 + 社区验证过的插件生态54%+ 移动 PWA 在用,框架官方推荐(Vite/Next/Angular 等)

一句话总结区别:

  • Service Worker = 浏览器提供的“发动机” → 功能强大,但原始、手动挡,开起来费力且容易翻车。
  • Workbox = Google 给的“自动挡 + 导航 + 辅助驾驶系统” → 让你把精力放在业务上,而不是跟生命周期和缓存边缘 case 死磕。

99% 的真实项目(尤其是中大型)都应该直接用 Workbox,除非你在做底层研究、极致性能调优或极小 demo。

Workbox 生产级示例(使用 vite-plugin-pwa,2026 年主流方式,基于 Workbox v7.4+):

// vite.config.ts
import { defineConfig } from 'vite'
import { VitePWA } from 'vite-plugin-pwa'

export default defineConfig({
  plugins: [
    VitePWA({
      registerType: 'autoUpdate',
      workbox: {
        globPatterns: ['**/*.{js,css,html,png,svg,ico}'], // 自动预缓存构建产物
        runtimeCaching: [
          // 图片:CacheFirst + 过期控制
          {
            urlPattern: /\.(?:png|jpg|jpeg|svg|webp|ico)$/,
            handler: 'CacheFirst',
            options: {
              cacheName: 'images-cache',
              expiration: {
                maxEntries: 60,
                maxAgeSeconds: 30 * 24 * 60 * 60, // 30 天
              },
            },
          },
          // API:StaleWhileRevalidate(快速显示旧数据 + 后台更新)
          {
            urlPattern: ({ url }) => url.pathname.startsWith('/api/'),
            handler: 'StaleWhileRevalidate',
            options: {
              cacheName: 'api-cache',
              plugins: [
                {
                  cacheWillUpdate: async ({ response }) => {
                    // 只缓存 0/200 响应
                    return response.status === 0 || response.status === 200 ? response : null;
                  },
                },
                {
                  expiration: {
                    maxEntries: 50,
                    maxAgeSeconds: 24 * 60 * 60, // 1 天
                  },
                },
              ],
            },
          },
          // 页面导航:NetworkFirst(优先新鲜内容)
          {
            urlPattern: ({ request }) => request.mode === 'navigate',
            handler: 'NetworkFirst',
            options: {
              cacheName: 'pages-cache',
              networkTimeoutSeconds: 3,
            },
          },
        ],
      },
      devOptions: { enabled: true }, // 本地开发也启用 SW
    }),
  ],
})

客户端注册 & 优雅更新(main.js):

import { registerSW } from 'virtual:pwa-register'

const updateSW = registerSW({
  onNeedRefresh() {
    // 可以显示 toast 或弹窗提示用户更新
    if (confirm('有新版本可用,是否立即更新?')) {
      updateSW(true)
    }
  },
  onOfflineReady() {
    console.log('应用已准备好离线使用')
  },
})

用 Workbox 后,sw.js 几乎不用手写,插件自动生成 + 维护,策略通过配置数组声明即可。