预缓存策略:提前把应用外壳送达
发布于
一句话: 预缓存在 service worker 的 install 步骤中,把一组已知、固定的文件存入 缓存,使应用外壳在被需要之前就已在设备上——安装后的首次导航能即时且离线地渲染。它是 运行时缓存的对应物,后者在用户请求时才存储响应。
预缓存对比运行时缓存
Section titled “预缓存对比运行时缓存”- 预缓存 —— 一份在构建时已知的固定清单(HTML 外壳、CSS、JS、图标、字体)。在
install期间、页面请求之前取回并存储。适合应用外壳及其他关键、始终需要的资源。 - 运行时缓存 —— 在
fetch处理器中随请求发生而填充,按选定的缓存策略进行。适合多变、 或太大/太多以致无法预先列出的内容(API 响应、用户图片、文章)。
预缓存与运行时缓存是互补的:预缓存外壳让首次加载快速且具备离线能力,并围绕它运行时缓存 动态内容。
预缓存什么(以及不缓存什么)
Section titled “预缓存什么(以及不缓存什么)”- 预缓存: 最小的应用外壳——渲染一个可用首屏所需的 HTML/CSS/JS 与图标。这里列出的一切
都会在
install事件期间被下载并存储。 - 改用运行时缓存: 多变、体积大或按需请求的内容,通常用运行时缓存策略处理,而非预缓存。
预缓存骨架;让运行时策略处理其余。
为何内容修订是核心问题
Section titled “为何内容修订是核心问题”只有当 service worker 能判断某个预缓存文件何时已变更,预缓存才安全。如果你预缓存了
/app.js,之后在同一 URL 部署了新的 /app.js,service worker 需要一个表明内容不同的信号,
否则用户会一直保留陈旧文件。
让变化可被检测的两种方式:
- 带版本的 URL(
/app.abc123.js):内容变化时 URL 本身就会变,因此预缓存条目自然是新 的。Workbox 会把一个已携带版本信息(如内容哈希)的 URL 视为其自身的修订。 - 每条目一个修订号: 把每个无版本的 URL(如
/index.html)与一个内容修订号配对,这样 即使 URL 相同,当修订号不同时缓存也会重新取回。
这套簿记正是构建期的预缓存清单所自动化的——手工维护极易出错,这也是为何预缓存通常委托 给库来做。
Workbox 预缓存的实践
Section titled “Workbox 预缓存的实践”Workbox 的 workbox-precaching 模块消费一份预缓存清单(构建期生成的 { url, revision } 条目
列表),并为你处理整个生命周期:
- 在
install期间,取回并存储每个列出的资源。 - 在
activate期间,移除先前预缓存中已不在清单里的条目,使旧外壳版本被自动清理。 - 它从缓存提供预缓存的响应,并在某条目的修订号变化时重新取回。
import { precacheAndRoute } from 'workbox-precaching';
// self.__WB_MANIFEST 在构建期被注入 { url, revision } 条目。precacheAndRoute(self.__WB_MANIFEST);Workbox 提供构建工具——workbox-build、workbox-webpack-plugin 与 workbox-cli——来从你
实际的构建产物生成该预缓存清单,使清单与修订号在每次部署时保持同步。
与 HTTP 缓存的关系
Section titled “与 HTTP 缓存的关系”预缓存存放于 Cache Storage 层,独立于浏览器的 HTTP 缓存。两者可能相互影响:一次预缓存取回 本身可能被 HTTP 缓存应答,从而把陈旧副本送进你的预缓存。在这种风险要紧之处,使用带版本的 URL,使每个版本都是不同的请求。留意两层的生命周期,别让它们彼此对抗。
- 只预缓存最小的应用外壳;动态与大型内容用运行时缓存。
- 优先使用带版本(哈希)的 URL,让变更的资源成为不同的请求。
- 对无版本的 URL(如
/index.html),将其与内容修订号配对。 - 用 Workbox 工具在构建期生成预缓存清单;不要手工维护这份列表。
- 依赖 Workbox 在
activate中清理被取代的预缓存。 - 警惕可能把陈旧资源预缓存进来的 HTTP 缓存交互。