缓存

缓存存储是一个强大的工具。降低应用对网络条件的依赖性。通过充分利用缓存,您可以让自己的网络应用离线使用,并在任何网络条件下尽快提供您的资产。如资产和数据中所述,您可以确定缓存必要资产的最佳策略。为了管理缓存,您的 Service Worker 与 Cache Storage API 进行交互。

浏览器支持

  • Chrome:43。 <ph type="x-smartling-placeholder">
  • Edge:16。 <ph type="x-smartling-placeholder">
  • Firefox:41。 <ph type="x-smartling-placeholder">
  • Safari:11.1. <ph type="x-smartling-placeholder">

来源

Cache Storage API 可在不同的上下文中使用:

  • 窗口上下文(PWA 的主线程)。
  • Service Worker。
  • 您使用的任何其他工作器。

使用 Service Worker 管理缓存的一个好处是,其生命周期不与窗口关联,这意味着您不会阻塞主线程。请注意,要使用 Cache Storage API,大多数此类上下文都必须通过 TLS 连接进行。

缓存内容

关于缓存,您的第一个问题可能是需要缓存的内容。虽然这个问题并无单一答案,但您可以先从呈现界面所需的所有最基本资源开始。

这些资源应包括:

  • 主页面 HTML(应用的 start_url)。
  • 主界面所需的 CSS 样式表。
  • 界面中使用的图片。
  • 呈现界面所需的 JavaScript 文件。
  • 呈现基本体验所需的数据(例如 JSON 文件)。
  • 网络字体。
  • 在多页应用中,您想要快速投放或离线时投放的其他 HTML 文档。

支持离线操作

虽然支持离线功能是渐进式 Web 应用的一项要求,但您必须了解,并非所有 PWA 都需要完整的离线体验,例如云游戏解决方案或加密资产应用。因此,您可以提供一个基本的用户界面,指导用户应对这些情况。

您的 PWA 不应呈现浏览器显示网页呈现引擎无法加载网页的错误消息。应改为使用 Service Worker 显示您自己的消息传递,从而避免一般和令人困惑的浏览器错误。

根据 PWA 的需求,您可以使用多种不同的缓存策略。因此,设计缓存使用方式以提供快速可靠的体验非常重要。例如,如果您的所有应用资源都能快速下载,不会占用大量空间,并且不需要在每次请求中都进行更新,那么缓存所有资源就是一种有效的策略。另一方面,如果您的资源需要为最新版本,您可以考虑不缓存这些资源。

使用此 API

使用 Cache Storage API 定义源站中的一组缓存,每个缓存都使用你可以定义的字符串名称进行标识。您可以通过 caches 对象访问 API,而 open 方法则可创建或打开已创建的缓存。open 方法为缓存对象返回一个 promise。

caches.open("pwa-assets")
.then(cache => {
  // you can download and store, delete or update resources with cache arguments
});

下载和存储资源

如需请求浏览器下载并存储资源,请使用 addaddAll 方法。add 方法可发出请求并存储一个 HTTP 响应,以及 addAll 一组 HTTP 响应作为基于请求或网址数组的事务。

caches.open("pwa-assets")
.then(cache => {
  cache.add("styles.css"); // it stores only one resource
  cache.addAll(["styles.css", "app.js"]); // it stores two resources
});

缓存存储接口会存储完整的响应内容,包括所有标头和正文。因此,您稍后可以使用 HTTP 请求或网址作为键来检索它。具体方法请参见“投放”一章

何时缓存

在 PWA 中,您可以决定何时缓存文件。虽然一种方法是在安装 Service Worker 时存储尽可能多的资源,但通常不是最好的选择。缓存不必要的资源会浪费带宽和存储空间,并且可能导致您的应用意外提供过时的资源。

您无需一次性缓存所有资源,可以在 PWA 的生命周期内多次缓存资源,例如:

  • 安装 Service Worker 时。
  • 在首次网页加载之后。
  • 当用户导航到某个路段或路线时。
  • 当网络空闲时。

您可以在主线程或 Service Worker 上下文中请求缓存新文件。

在 Service Worker 中缓存资源

最常见的一种方案是在安装 Service Worker 时缓存最少的资源集。为此,您可以在 Service Worker 的 install 事件中使用缓存存储接口。

由于 Service Worker 线程可以随时停止,因此您可以请求浏览器等待 addAll promise 完成,以增加存储所有资源并保持应用一致性的机会。以下示例演示了如何使用在 Service Worker 事件监听器中收到的事件参数的 waitUntil 方法执行此操作。

const urlsToCache = ["/", "app.js", "styles.css", "logo.svg"];
self.addEventListener("install", event => {
   event.waitUntil(
      caches.open("pwa-assets")
      .then(cache => {
         return cache.addAll(urlsToCache);
      });
   );
});

waitUntil() 方法收到一个 promise 并要求浏览器等待该 promise 中的任务完成解析(已执行或失败),然后再终止 Service Worker 进程。您可能需要串联 promise 并返回 add()addAll() 调用,以便只有一个结果到达 waitUntil() 方法。

您还可以使用 async/await 语法处理 promise。在这种情况下,您需要创建一个可以调用 await 并在调用后向 waitUntil() 返回 promise 的异步函数,如以下示例所示:

const urlsToCache = ["/", "app.js", "styles.css", "logo.svg"];
self.addEventListener("install", (event) => {
   let cacheUrls = async () => {
      const cache = await caches.open("pwa-assets");
      return cache.addAll(urlsToCache);
   };
   event.waitUntil(cacheUrls());
});

跨网域请求和不透明响应

您的 PWA 可以从源站和跨网域下载和缓存资源,例如来自第三方 CDN 的内容。对于跨网域应用,缓存交互与同源请求非常相似。系统会执行请求,并在缓存中存储响应的副本。与其他缓存的资源一样,它只能在应用的源中使用。

该资源将存储为不透明响应,这意味着您的代码将无法查看或修改该响应的内容或标头。此外,不透明响应不会在 Storage API 中公开其实际大小,这会影响配额。有些浏览器会显示大小上限,例如 7Mb,而无论文件大小仅为 1Kb。

更新和删除资产

您可以使用 cache.put(request, response) 更新资产,也可以使用 delete(request) 删除资产。

如需了解详情,请参阅缓存对象文档

调试 Cache Storage

许多浏览器都提供了一种在开发者工具 Application 标签中调试缓存存储内容的方法。在这里,您可以看到当前源中每个缓存的内容。我们将在“工具和调试”一章中详细介绍这些工具。

Chrome 开发者工具调试 Cache Storage 内容。

资源