处理导航请求

使用 Service Worker 响应导航请求,而无需等待网络。

导航请求是指每当您在导航栏中输入新网址,或点击页面上的链接转到新网址时,浏览器发出的 HTML 文档请求。这就是 Service Worker 对性能产生最大影响的原因:如果您使用 Service Worker 响应导航请求而不等待网络,那么除了在网络不可用时保持弹性,您还可以确保导航能够快速可靠地进行响应。这是 Service Worker 实现的最大性能优势,而 HTTP 缓存则可以实现这一目标。

识别从网络加载的资源指南中所述,导航请求是在网络流量的“瀑布”中发出的可能很多请求中的第一个。通过导航请求加载的 HTML 将启动对图片、脚本和样式等子资源的任何其他请求流。

在 Service Worker 的 fetch 事件处理脚本内,您可以通过检查 FetchEvent 上的 request.mode 属性来确定请求是否为导航。如果它设置为 'navigate',则它是导航请求。

一般来说,请勿使用长期有效的 Cache-Control headers 缓存导航请求的 HTML 响应。通常应通过网络通过 Cache-Control: no-cache 来满足请求,以确保 HTML 以及后续网络请求链是(合理)最新的。遗憾的是,每当用户导航到新页面时都会访问网络,意味着每次导航可能都会变慢。至少,这意味着运行速度会不太稳定。

不同的架构方法

想要知道如何响应导航请求并避开网络可能很棘手。正确的方法在很大程度上取决于您网站的架构以及用户可能会导航到的唯一网址的数量。

虽然没有放之四海而皆准的解决方案,但以下常规准则应该可以帮助您确定哪种方法最可行。

小型静态网站

如果您的 Web 应用包含数量相对较少(假设:数十个)唯一网址,并且其中每个网址都对应于一个不同的静态 HTML 文件,那么一种可行的方法是仅缓存所有这些 HTML 文件,然后使用适当的缓存 HTML 响应导航请求。

使用预缓存,您可以在安装 Service Worker 后立即缓存 HTML,并在每次重新构建网站并重新部署 Service Worker 时更新缓存的 HTML。

或者,如果您希望避免预缓存所有 HTML(或许是因为用户往往只会转到您网站上的部分网址),则可以使用 stale-while-revalidate 运行时缓存策略。不过,请谨慎使用该方法,因为每个 HTML 文档都是单独缓存和更新的。如果您有少量网址被同一组用户频繁再次访问,并且您愿意单独对这些网址进行重新验证,那么为 HTML 使用运行时缓存是最合适的选择。

单页应用

现代 Web 应用经常使用单页架构。在该机制中,客户端 JavaScript 会修改 HTML 以响应用户操作。此模型使用 History API,在用户与 Web 应用交互时修改当前网址,从而实现实际的“模拟”导航。虽然后续导航可能是“虚假”的,但初始导航是真实的,仍请务必确保它在网络中未被屏蔽。

幸运的是,如果您使用的是单页架构,可以通过一种简单的模式(即 Application Shell)从缓存提供初始导航。在此模型中,无论请求什么网址,您的 Service Worker 通过返回已预缓存的同一 HTML 文件来响应导航请求。该 HTML 应该是准系统,由常规加载指示器或框架内容组成。浏览器从缓存中加载此 HTML 后,现有的客户端 JavaScript 将接管,并呈现原始导航请求中网址的正确 HTML 内容。

Workbox 提供了实现此方法所需的工具;navigateFallback option 可让您指定要用作 App Shell 的 HTML 文档,以及可选的允许和拒绝列表,可将此行为限定为您的一部分网址。

多页应用

如果您的网络服务器会动态生成网站的 HTML,或者如果您有数十个不同的网页,那么在处理导航请求时,要避开网络会困难得多。其他中的建议可能适用于您。

但对于多页应用的特定子集,您或许可以实现一个 Service Worker,它完全复制您的 Web 服务器中用于生成 HTML 的逻辑。如果您可以在服务器和 Service Worker 环境之间共享路由和模板信息,尤其是当您的 Web 服务器使用 JavaScript(不依赖于文件系统访问等特定于 Node.js 的功能)时,此方法会效果最佳。

如果您的网络服务器属于该类别,并且您希望探索一种方法来将 HTML 生成从网络转移到 Service Worker,请参阅 SPA 以外:PWA 的备用架构中的指南。

其他

如果您无法使用缓存的 HTML 响应导航请求,则必须采取措施,以确保向网站添加 Service Worker(处理其他非 HTML 请求)最终不会减慢导航速度。如果在不使用 Service Worker 响应导航请求的情况下启动 Service Worker,则会导致少量延迟(如使用 Service Worker 构建更快、弹性更佳的应用中所述)。为减少此开销,您可以启用一项名为导航预加载的功能,然后使用已预加载到 fetch 事件处理脚本中的网络响应

Workbox 提供了一个帮助程序库,用于检测是否支持导航预加载;如果支持,则可简化告知 Service Worker 使用网络响应的过程。

摄影:Aaron BurdenUnsplash 用户