使用 Service Worker

此代码实验室将向您展示如何从 Web 应用中注册服务工作线程,以及如何使用 Chrome DevTools 观察其行为。其中还介绍了一些调试技巧,这些技巧在处理服务工作线程时可能会很有用。

熟悉示例项目

示例项目中与此 Codelab 最相关的文件如下:

  • register-sw.js 最初为空,但将包含用于注册服务工作线程的代码。它已通过项目 index.html 内的 <script> 标记加载。
  • service-worker.js 同样为空。该文件将包含此项目的服务工件。

添加 Service Worker 注册代码

除非先注册,否则系统不会使用服务工作线程(即使是空的服务工作线程,例如当前的 service-worker.js 文件)。您可以通过调用以下方法来实现此目的:

navigator.serviceWorker.register(
  '/service-worker.js'
)

在您的 register-sw.js 文件中。

不过,在添加该代码之前,您需要考虑以下几点。

首先,并非所有浏览器都支持服务工作线程。对于不会自动更新的旧版浏览器,这一点尤为重要。因此,最佳实践是在检查是否支持 navigator.serviceWorker 后有条件地调用 navigator.serviceWorker.register()

其次,当您注册服务工作器时,浏览器会运行 service-worker.js 文件中的代码,并且可能会开始下载网址以填充缓存,具体取决于服务工作器的 installactivate 事件处理程序中的代码。

运行额外的代码和下载资源可能会耗用浏览器原本可用于显示当前网页的重要资源。为避免这种干扰,最好延迟注册服务工件,直到浏览器完成当前页面的呈现。若要近似地实现此操作,一种方便的方法是等待 window.load 事件触发。

将这两点结合起来,将以下通用服务工注册代码添加到 register-sw.js 文件中:

if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/service-worker.js');
  });
}

添加一些 Service Worker 日志记录代码

service-worker.js 文件通常是服务工件实现的所有逻辑所在的位置。您可以结合使用服务工件生命周期事件Cache Storage API 以及 Web 应用网络流量方面的知识,打造出精心设计的服务工件,随时处理 Web 应用的所有请求。

不过…这些内容留待以后再学。在此阶段,重点是观察各种服务工作线程事件,并熟练使用 Chrome 的 DevTools 调试服务工作线程的状态。

为此,请将以下代码添加到 service-worker.js,该代码会在响应各种事件时将消息记录到 DevTools 控制台(但不会执行其他操作):

self.addEventListener('install', (event) => {
  console.log('Inside the install handler:', event);
});

self.addEventListener('activate', (event) => {
  console.log('Inside the activate handler:', event);
});

self.addEventListener(fetch, (event) => {
  console.log('Inside the fetch handler:', event);
});

熟悉 DevTools 中的“Service Workers”面板

现在,您已将代码添加到 register-sw.jsservice-worker.js 文件中,接下来可以访问示例项目的正式版,并观察服务工件的工作情况。

  • 如需预览网站,请按 View App(查看应用)。然后按 Fullscreen(全屏)全屏
  • 按 `Control+Shift+J`(在 Mac 上为 `Command+Option+J`)打开 DevTools。
  • 点击控制台标签页。

您应该会看到类似以下日志消息的内容,表明服务工件已安装并激活:

显示 Service Worker 已安装并激活。

然后,访问 Applications(应用)标签页,然后选择 Service Workers(服务工作器)面板。您应看到类似下图的内容:

在 Service Worker 面板中显示 Service Worker 详情。

这表示,对于 Web 应用 solar-donkey.glitch.me,有一个源网址为 service-worker.js 的服务工作线程目前处于启用和运行状态。它还会告知您当前有 1 个客户端(打开的标签页)由该服务工作器控制。

您可以使用此面板上的链接(例如 Unregisterstop)更改当前注册的服务工作器,以进行调试。

触发服务工件更新流程

使用服务工作线程进行开发时,需要了解的一个关键概念是更新流程

用户访问注册了服务工件的 Web 应用后,他们最终会获得在其本地浏览器上安装的当前 service-worker.js 副本的代码。但是,如果您更新存储在 Web 服务器上的 service-worker.js 版本,会发生什么情况?

当回访者返回到 Service Worker 范围内的网址时,浏览器会自动请求最新的 service-worker.js 并检查是否有任何更改。如果 Service Worker 脚本中的任何内容都不同,则新 Service Worker 将有机会安装、激活并最终取得控制权。

您可以通过返回项目的代码编辑器并对代码进行任何更改来模拟此更新流程。一个快速更改是替换

self.addEventListener('install', (event) => {
  console.log('Inside the install handler:', event);
});

通过

self.addEventListener('install', (event) => {
  console.log('Inside the UPDATED install handler:', event);
});

进行更改后,返回示例应用的正式版,然后在 DevTools 的“Application”标签页仍处于打开状态时重新加载页面。您应该会看到类似以下内容:

显示已安装的两个版本的 Service Worker。

这表明此时已安装两个版本的 Service Worker。已激活的旧版正在运行,并控制着当前页面。下面列出了更新后的服务工件版本。它处于 waiting 状态,并会一直等待,直到由旧服务工作线程控制的所有打开的标签页都关闭为止。

此默认行为可确保,如果您的新服务工件与旧服务工件的行为存在根本差异(例如,fetch 处理脚本使用与旧版 Web 应用不兼容的资源进行响应),则在用户关闭 Web 应用的所有之前实例之前,新服务工件不会生效。

总结

现在,您应该已经熟悉了注册服务工作线程以及使用 Chrome 的 DevTools 观察服务工作线程行为的流程。

现在,您已经做好了开始实现缓存策略以及所有有助于 Web 应用可靠快速加载的优化措施的准备。