处理导航请求

使用服务工件响应导航请求,而无需等待网络响应。

导航请求是指每当您在导航栏中输入新网址,或点击网页上的链接转到新网址时,浏览器发出的 HTML 文档请求。服务工件对性能的影响最显著的就是在这一点上:如果您使用服务工件响应导航请求,而无需等待网络,则不仅可以确保导航速度可靠地快,还可以在网络不可用时保持弹性。与 HTTP 缓存相比,这是服务工件带来的单项最大性能提升。

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

在服务工件的 fetch 事件处理脚本中,您可以通过检查 FetchEvent 上的 request.mode 属性来确定请求是否为导航。如果将其设置为 'navigate',则表示导航请求。

一般而言,请勿使用长效 Cache-Control headers 缓存导航请求的 HTML 响应。通常,这些条件应通过网络使用 Cache-Control: no-cache 来满足,以确保 HTML 以及后续网络请求链(在合理范围内)保持新鲜。遗憾的是,每次用户导航到新网页时都与网络进行交互,这意味着每次导航都可能很慢。至少,这意味着速度不会可靠地快。

架构的不同方法

确定如何在避免使用网络的情况下响应导航请求可能很棘手。合适的方法在很大程度上取决于您网站的架构以及用户可能会导航到的唯一网址数量。

虽然没有放之四海而皆准的方法,但以下一般准则应该有助于您确定哪种方法最可行。

小型静态网站

如果您的 Web 应用包含相对较少(例如几十个)的唯一网址,并且每个网址对应于不同的静态 HTML 文件,那么一种可行的方法是只缓存所有这些 HTML 文件,并使用相应的缓存 HTML 响应导航请求。

借助预缓存,您可以在服务工件安装后立即预先缓存 HTML,并在每次重新构建网站和重新部署服务工件时更新缓存的 HTML。

或者,如果您不想预缓存所有 HTML(可能是因为用户往往只会浏览您网站上的部分网址),则可以使用“在重新验证期间使用过时数据”运行时缓存策略。不过,请谨慎使用此方法,因为每个单独的 HTML 文档都会单独缓存和更新。如果您有少量网址会被同一组用户经常访问,并且您不介意这些网址彼此独立重新验证,那么对 HTML 使用运行时缓存最为合适。

单页应用

单页面架构经常被现代 Web 应用使用。在其中,客户端 JavaScript 会根据用户操作修改 HTML。此模型会在用户与 Web 应用互动时使用 History API 修改当前网址,从而有效地实现“模拟”导航。虽然后续导航可能是“虚假”导航,但初始导航是真实的,因此请务必确保网络上未屏蔽该导航。

幸运的是,如果您使用的是单页面架构,则可以通过一种简单的模式从缓存中提供初始导航:应用 shell。在此模型中,无论请求的网址如何,您的服务工件都会通过返回已预缓存的同一 HTML 文件来响应导航请求。此 HTML 应为基本 HTML,可能包含通用加载指示器或框架内容。浏览器从缓存中加载此 HTML 后,现有的客户端 JavaScript 会接管,并针对原始导航请求中的网址呈现正确的 HTML 内容。

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

多页应用

如果您的网络服务器会动态生成您网站的 HTML,或者您有超过几十个唯一网页,那么在处理导航请求时,要想避免使用网络就更难了。其他部分中的建议可能适用于您。

不过,对于某些多页面应用,您或许可以实现一个 Service Worker,以完全复制 Web 服务器中用于生成 HTML 的逻辑。如果您可以在服务器和服务工件环境之间共享路由和模板信息,这种方法最适合,尤其是在您的网络服务器使用 JavaScript(而不依赖于 Node.js 专用功能,例如文件系统访问)时。

如果您的 Web 服务器属于此类别,并且您希望探索将 HTML 生成从网络迁移到服务工件的一种方法,可以参阅超越 SPA:PWA 的替代架构中的指南,开始探索。

其他

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

Workbox 提供了一个辅助库,用于通过功能检测是否支持导航预加载,如果支持,则简化了告知您的服务工件使用网络响应的过程。

照片由 Aaron Burden 拍摄,选自 Unsplash