部署 Service Worker 可能会以意想不到的方式改变网站的行为。由于 Workbox 可让您轻松编写和部署 Service Worker,因此 Service Worker 在部署后会更容易忽略其对网站产生的某些影响。
这并不意味着使用 Workbox 会产生不良结果,只不过它提供的便利性可能会使如果您不了解部署 Service Worker 会带来哪些问题,更容易陷入一些陷阱。
预缓存误区
这些文档之前已介绍预缓存,但并未全面说明该做法如何逆反。如果您对过多的资产应用预缓存,或者如果在页面有机会完成关键资产的加载之前就注册了 Service Worker,就可能会遇到问题。
由于 workbox-webpack-plugin
的默认行为是指示 Service Worker 自动预缓存生成的资源,因此这可能会出现问题,并且很容易被忽视,因为采用的门槛很低。
![终端输出。](https://developer.chrome.google.cn/static/docs/workbox/service-worker-deployment/image/terminal-output-6714930555301.png?authuser=6&hl=lt)
workbox-webpack-plugin.
的终端输出
在此示例中,它会预缓存当前项目中的 14 项资产,默认情况下共缓存 352 千字节。当 Service Worker 在安装过程中预缓存资源时,会同时启动一个或多个网络请求。如果时间不合适,可能会给用户体验带来问题。 即使时机恰到好处,但如果预缓存资产的数量没有在某种程度上加以限制,它仍然可能浪费数据。
一切由时机决定
如果 Service Worker 预缓存任何内容,那么它的注册时间就很重要。Service Worker 通常使用内嵌 <script>
元素进行注册。这意味着,HTML 解析器可能会在页面的关键资源加载之前发现 Service Worker 注册代码。
这是一个问题。理想情况下,Service Worker 在最糟糕的情况下应该保持性能中立,而不是降低性能。用户最好,并在页面的 load
事件触发时注册 Service Worker。这样可以降低预缓存干扰加载网页关键资源的几率,反过来意味着页面可以更快地进行交互,无需与网络请求争用可能不需要的资源,直到稍后才不需要。
考虑流量消耗
无论何时,预缓存都涉及分派网络请求。如果未经仔细挑选要预缓存的资产清单,可能会造成一些浪费。
虽然数据浪费可能需要进行预缓存的权衡,但并非每个人都可以访问快速互联网,甚至没有无限量的流量套餐!预缓存时,请考虑删减特别大的资源并依靠运行时缓存来捕获这些资源,而不是做出代价高昂的假设。
Service Worker 启动可能会延迟网络请求
Service Worker 在独立于网站代码其余部分的进程中运行。此过程经常开始和停止。当 Service Worker 处于非活跃状态后需要处理 fetch 事件时,浏览器首先需要花时间启动 Service Worker。与从缓存而非网络提供响应的好处相比,这种在请求处理之前的额外开销很小。
当使用无法从缓存传送且必须转到网络的策略时(尤其是在处理导航请求时),启动时间总是会造成一些延迟。根据设备功能和/或 CPU 压力,导航请求可能会因 Service Worker 启动缓慢而出现明显的延迟。如果在不知道此延迟的情况下部署 Service Worker,则用户可能会遇到性能意外下降的情况。
该问题已通过导航预加载解决,但并非所有浏览器都支持该功能。不过,它的使用值得考虑,本文档稍后会对此进行介绍。
缓存优先策略可能会适得其反
先查询缓存或仅查询缓存的缓存策略对离线访问和性能都非常有利。 但在某些情况下,它们往往会导致出现问题。
未版本化的静态资源的运行时缓存
捆绑器通常会对文件名中包含基于内容的哈希(例如 styles.a4edf38c.css
)的静态资源进行版本化处理。在 Service Worker 使用会首先查询缓存来寻找静态资源,并对页面标记使用网络优先策略的缓存策略,应该不会出现缓存问题,因为更新的资源是在始终从网络检索的标记中引用的。
如果使用这些策略在运行时期间缓存未版本化的静态资源,则会出现问题。
如果网站的功能由 app.js
提供,并且采用了缓存优先运行时策略,则 app.js
稍后会更新,其文件名不变,那么最初缓存的版本将会继续通过缓存提供,而不会进行更新。
解决方案是使用查询网络以进行更新的策略,例如网络优先或过时同时重新验证。或者,构建工具可以为这些资源生成预缓存清单,因为 Workbox 的预缓存逻辑会使其保持最新。
但无论如何,强烈建议您对静态资源进行版本控制,无论是通过资源名称中的哈希,还是查询字符串。这样可避免在针对静态资源使用缓存优先运行时策略的 Service Worker 中与过时资源相关的问题。
注意存储空间配额
不时发布 Service Worker 更新是一种很常见的做法,当发布更新时,名称已过期的旧缓存通常会在新 Service Worker 激活期间删除。
但是,某些 Service Worker 迭代是长期存在的,或者缓存名称可能无法在新的更新中更新。如果发生这种情况,旧的静态资源会在更新发布时堆积在缓存中。浏览器会设置存储空间配额和限制。这就是值得关注的理由!
Workbox 可以很好地缓解这些问题,但仍然可能会超出存储空间配额。您可以使用 workbox-expiration 模块对缓存实现更精细的控制。
不必担心
部署 Service Worker 可不是小事。 然而,如果要使用 Workbox 部署 Service Worker,需要有一定的规划和正念,这不应该是一个可怕的壮举。 随着您不断深入,本文档将帮助您自信地解决这些疑虑。