Service Workers 缓存 API 与 Fetch 事件解析 - Francisco Brusa

作者:API传播员 · 2025-11-14 · 阅读时间:4分钟
Service Worker 是一种独立于浏览器主线程的脚本,能够拦截网络请求并利用缓存 API 实现请求/响应存储。文章详细解析了缓存 API 的基本用法、Fetch 事件的触发条件,以及如何应用缓存优先策略处理图像和脚本资源,帮助开发者优化离线支持和性能。

Service Workers 缓存 API 和 Fetch 事件解析

Service Worker 是一种运行在独立于浏览器主线程的环境中的脚本。它的特点是每个域只运行一次,而不是每个浏览器选项卡都运行一次。当页面刷新时,如果没有加载特定的脚本标记,它不会再次执行。例如,以下代码可以注册一个 Service Worker:

navigator.serviceWorker.register("/serviceWorker.js");

Service Worker 的请求拦截能力

Service Worker 可以拦截任何出站网络请求,无论是浏览器尝试从其他域获取资源,还是在离线状态下发起请求。这包括通过 GET 或 POST 方法获取的脚本、图像或 HTML 文档等资源。

在拦截请求时,您可以对响应进行多种操作,例如:

  • 发起实际的网络请求并将响应存储到缓存中。
  • 从缓存中检索之前的响应版本。
  • 修改响应的内容、标题或状态码(尽管不建议这样做)。

缓存 API(WindowOrWorkerGlobalScope.caches)

缓存 API 是一个基于请求/响应键值对的存储机制。虽然大多数示例都展示了如何在 Service Worker 中使用缓存 API(如 caches.open()),但实际上它也可以在普通的 JavaScript 环境中使用。

缓存 API 的基本用法

为了更好地理解缓存 API,我们可以从以下几个方面入手:

  1. Request 类与 fetch 函数的结合

    Request 类与 fetch 函数的签名一致,因此可以直接使用 Request 对象调用 fetch 函数。此外,您可以使用 Request 和 Response 对象向缓存中添加条目。

  2. 从缓存中检索条目

    您可以通过将缓存条目与类似的 Request 对象进行匹配,从缓存中检索相应的条目。值得注意的是,缓存 API 会自动处理请求对象的序列化问题。

  3. 浏览器环境中的使用

    缓存 API 不仅限于 Service Worker 环境,也可以在支持 fetch 函数的浏览器环境中使用。

以下是一个在浏览器和 Service Worker 中都有效的函数示例,该函数实现了 Workbox 中的“缓存优先”策略:

async function fetchUsingCacheFirstStrategy(request) {
  const cache = await caches.open('my-cache');
  const cachedResponse = await cache.match(request);
  if (cachedResponse) {
    return cachedResponse;
  }
  const networkResponse = await fetch(request);
  await cache.put(request, networkResponse.clone());
  return networkResponse;
}

需要注意的是,上述示例未考虑缓存失效问题,因此不适合直接用于生产环境。


Fetch 事件与缓存策略

Service Worker 的强大之处在于它可以通过 self.addEventListener("fetch") 监听 FetchEvent 类型的事件。这种方式不仅适用于 JavaScript 发起的 XHR 请求,还可以对浏览器加载脚本、样式表、图像等资源的请求应用缓存策略

Fetch 事件的触发条件

Fetch 事件会在浏览器发出的任何请求时触发,包括:

  • 使用 fetch() 发起的请求。
  • 通过 XMLHttpRequest 发起的请求。
  • 由 HTML 标签(如 <img><link><svg>)触发的请求。

在监听 Fetch 事件时,实际的请求会被拦截,只有在明确允许的情况下才会发出。这意味着您可以完全控制请求的执行。例如,以下代码为所有出站请求添加了一个自定义标头:

self.addEventListener('fetch', event => {
  event.respondWith(
    fetch(event.request, {
      headers: {
        'Custom-Header': 'MyHeaderValue'
      }
    })
  );
});

缓存优先策略的应用

结合缓存 API,可以使用缓存优先策略处理特定类型的请求。例如,以下代码为所有图像请求应用缓存优先策略:

self.addEventListener('fetch', event => {
  if (event.request.destination === 'image') {
    event.respondWith(
      caches.open('image-cache').then(cache =>
        cache.match(event.request).then(cachedResponse =>

          cachedResponse || fetch(event.request).then(networkResponse => {            cache.put(event.request, networkResponse.clone());
            return networkResponse;
          })
        )
      )
    );
  }
});

结论

缓存 API 是一个强大的工具,可以在浏览器和 Service Worker 中使用。然而,只有在 Service Worker 中,您才能完全控制非 XHR 请求(如图像、样式表等)的处理方式。

这意味着,您可以先在浏览器中使用缓存 API 处理部分 API 调用,然后在需要缓存非 API 调用(或提供离线支持)时,将其集成到 Service Worker 中,从而实现更高级的功能。

原文链接: https://www.franciscobrusa.dev/blog/service-workers-cache