服务工作线程

用户希望应用在缓慢或不稳定的网络连接,甚至离线状态下都能可靠启动。他们希望最近互动过的内容,例如媒体曲目或票证和行程,都可用且可使用。当请求不可行时,他们希望应用告知他们,而不是静默失败或崩溃。并且他们希望所有这些都快速发生。正如您在“毫秒成就百万美元”中看到的那样,即使加载时间缩短 0.1 秒,转化率也可能提高多达 10%。服务工作线程是让您的 PWA 满足用户期望的工具。

A service worker as a middleware proxy, running device-side, between your PWA and servers, which includes both your own servers and cross-domain servers.
服务工作线程充当您的 PWA 与其交互的服务器之间的中间件。

当应用请求服务工作线程作用域内的资源时,即使在用户离线的情况下,服务工作线程也会拦截请求并充当网络代理。然后,它可以决定是从使用 Cache Storage API 的缓存中提供资源,还是像没有活动服务工作线程一样从网络中提供资源,或者从本地算法创建资源。这使您可以提供高质量的体验,就像平台应用一样,即使您的应用处于离线状态。

注册服务工作线程

在服务工作线程控制您的页面之前,必须为您的 PWA 注册它。这意味着用户首次打开您的 PWA 时,其所有网络请求都直接发送到您的服务器,因为服务工作线程尚未控制您的页面。

在检查浏览器是否支持 Service Worker API 后,您的 PWA 可以注册服务工作线程。加载后,服务工作线程会在您的 PWA 和网络之间设置自身,拦截请求并提供相应的响应。

if ('serviceWorker' in navigator) {
   navigator.serviceWorker.register("/serviceworker.js");
}
尝试注册服务工作线程,看看您的浏览器开发者工具中会发生什么。

验证是否已注册服务工作线程

要验证是否已注册服务工作线程,请在您喜欢的浏览器中使用开发者工具。

在 Firefox 和基于 Chromium 的浏览器(Microsoft Edge、Google Chrome 或 Samsung Internet)中

  1. 打开开发者工具,然后点击 Application 选项卡。
  2. 在左侧窗格中,选择 Service Workers
  3. 检查服务工作线程的脚本 URL 是否显示状态为“已激活”。(有关更多信息,请参阅“生命周期”)。在 Firefox 上,状态可以是“正在运行”或“已停止”。

在 Safari 中

  1. 点击 Develop > Service Workers
  2. 检查此菜单中是否包含当前来源的条目。点击该条目会打开服务工作线程上下文的检查器。
Service worker developer tools on Chrome, Firefox and Safari.
Chrome、Firefox 和 Safari 上的服务工作线程开发者工具。

作用域

您的服务工作线程所在的文件夹决定了其作用域。位于 example.com/my-pwa/sw.js 的服务工作线程可以控制 my-pwa 路径或其下的任何导航,例如 example.com/my-pwa/demos/。服务工作线程只能控制其作用域内的项目(页面、工作线程,统称为“客户端”)。此作用域适用于浏览器标签页和 PWA 窗口。

每个作用域只允许一个服务工作线程。当服务工作线程处于活动状态并运行时,无论内存中有多少客户端(PWA 窗口或浏览器标签页),通常只有一个实例可用。

Safari 具有更复杂的作用域管理(称为分区),这会影响作用域如何与跨域 iframe 一起工作。要了解有关 WebKit 实现的更多信息,请参阅他们的博客文章

生命周期

服务工作线程具有一个生命周期,该生命周期决定了它们的安装方式,这与您的 PWA 安装是分开的。

服务工作线程生命周期从注册服务工作线程开始。然后,浏览器尝试下载并解析服务工作线程文件。如果解析成功,则会触发服务工作线程的 install 事件。install 事件只触发一次。

服务工作线程安装是静默发生的,无需用户许可,即使在用户未安装 PWA 的情况下也是如此。即使在不支持 PWA 安装的平台(例如桌面设备上的 Safari 和 Firefox)上,Service Worker API 也可用。

安装后,服务工作线程需要激活才能控制其客户端,包括您的 PWA。当服务工作线程准备好控制其客户端时,会触发 activate 事件。但是,默认情况下,已激活的服务工作线程无法管理注册它的页面,直到您下次通过重新加载页面或重新打开 PWA 导航到该页面为止。

您可以使用 self 对象在服务工作线程的全局作用域中监听事件。

serviceworker.js

// This code executes in its own worker or thread
self.addEventListener("install", event => {
   console.log("Service worker installed");
});
self.addEventListener("activate", event => {
   console.log("Service worker activated");
});

更新服务工作线程

当浏览器检测到控制客户端的服务工作线程和来自服务器的新版本服务工作线程文件字节不同时,服务工作线程会得到更新。

成功安装后,新的服务工作线程会等待激活,直到旧的服务工作线程不再控制任何客户端。此状态称为“等待”,浏览器正是通过这种方式确保一次只运行一个版本的服务工作线程。

刷新页面或重新打开 PWA 不会使新的服务工作线程取得控制权。用户必须关闭或导航离开所有使用当前服务工作线程的标签页和窗口,然后导航返回以使新的服务工作线程获得控制权。有关更多信息,请参阅“服务工作线程生命周期”

服务工作线程生命周期

已安装和注册的服务工作线程可以管理其作用域内的所有网络请求。它在自己的线程上运行,其激活和终止由浏览器控制,这使其即使在您的 PWA 打开之前或关闭之后也能工作。服务工作线程在自己的线程上运行,但内存中的状态可能不会在服务工作线程的运行之间持久存在,因此请确保您要为每次运行重用的任何内容都可以在 IndexedDB 或其他一些持久存储中获得。

如果服务工作线程尚未运行,则每当在其作用域内发送网络请求,或者当它收到触发事件(如定期后台同步或推送消息)时,它就会启动。

如果服务工作线程空闲了几秒钟,或者如果它繁忙时间过长,则会被终止。这种情况的计时因浏览器而异。如果服务工作线程已被终止,并且发生了会启动它的事件,则它会重新启动。

功能

已注册和激活的服务工作线程使用一个线程,该线程的执行生命周期与您的 PWA 主线程完全不同。但是,默认情况下,服务工作线程文件本身没有行为。它不会缓存或提供任何资源;这些是您的代码需要做的事情。您将在以下章节中了解如何操作。

服务工作线程的功能不仅用于代理或服务 HTTP 请求。在其之上还提供其他功能,用于其他目的,例如后台代码执行、Web 推送通知和处理付款。我们将在“功能”中讨论这些新增功能。

资源