Service Worker

用户希望应用在网速较慢或不稳定的情况下能可靠地启动,甚至在离线状态下也能正常启动。他们希望最近互动过的内容(例如媒体曲目或票券和行程)能够正常使用。当无法发出请求时,用户希望应用通知他们,而不是静默失败或崩溃。他们希望这一切都快速完成。正如毫秒提升数百万所示,即使加载时间缩短 0.1 秒,转化率也可以提高多达 10%。Service Worker 是一种工具,可让您的渐进式 Web 应用 (PWA) 达到用户的预期。

Service Worker 作为中间件代理,在 PWA 与服务器(包括您自己的服务器和跨网域服务器)之间在设备端运行。
Service Worker 充当 PWA 与其交互服务器之间的中间件。

当应用请求 Service Worker 的作用域涵盖的资源时,即使用户处于离线状态,Service Worker 也会拦截请求并充当网络代理。然后,它可以决定是使用 Cache Storage API 从缓存提供资源,还是通过网络(就像没有活跃的 Service Worker 一样)提供资源,或者通过本地算法创建资源。这样,即使您的应用处于离线状态,您也可以提供像平台应用那样的优质体验。

注册 Service Worker

必须先为您的 PWA 注册 Service Worker,才能控制您的页面。这意味着用户首次打开您的 PWA 时,其所有网络请求都会直接转到您的服务器,因为 Service Worker 尚不能控制您的网页。

检查浏览器是否支持 Service Worker API 后,您的 PWA 可以注册一个 Service Worker。加载后,Service Worker 会在 PWA 与网络之间自行设置,拦截请求并提供相应的响应。

if ('serviceWorker' in navigator) {
   navigator.serviceWorker.register("/serviceworker.js");
}
尝试注册一个 Service Worker,然后在浏览器的开发者工具中看看会发生什么。

验证 Service Worker 是否已注册

如需验证 Service Worker 是否已注册,请在您偏好的浏览器中使用开发者工具。

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

  1. 打开开发者工具,然后点击应用标签页。
  2. 在左侧窗格中,选择 Service Workers
  3. 检查 Service Worker 的脚本网址是否显示为“Activated”(已激活)状态。(如需了解详情,请参阅生命周期)。在 Firefox 上,状态可以是“正在运行”或“已停止”。

在 Safari 中:

  1. 点击 Develop > Service Workers
  2. 检查此菜单中是否有包含当前源的条目。点击该条目会在 Service Worker 的上下文上打开一个检查器。
Chrome、Firefox 和 Safari 上的 Service Worker 开发者工具。
Chrome、Firefox 和 Safari 上的 Service Worker 开发者工具。

范围

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

每个范围仅允许 1 个 Service Worker。当 Service Worker 处于活跃状态且正在运行时,无论内存中有多少客户端(PWA 窗口或浏览器标签页),通常只有一个实例可用。

Safari 具有更复杂的范围管理(称为分区),会影响范围与跨网域 iframe 配合使用的方式。如需详细了解 WebKit 的实现,请参阅他们的博文

生命周期

Service Worker 的生命周期决定了它们的安装方式,它们与您的 PWA 安装分开。

Service Worker 生命周期从注册 Service Worker 开始。然后,浏览器会尝试下载并解析 Service Worker 文件。如果解析成功,则会触发 Service Worker 的 install 事件。install 事件仅触发一次。

Service Worker 会静默安装,无需用户权限,即使用户未安装 PWA 也是如此。即使在不支持安装 PWA 的平台(例如桌面设备上的 Safari 和 Firefox)上,也可以使用 Service Worker API。

安装后,必须先激活 Service Worker,然后才能控制其客户端(包括 PWA)。当 Service Worker 准备好控制其客户端时,会触发 activate 事件。但在默认情况下,已激活的 Service Worker 无法管理注册它的页面,直到您下次通过重新加载页面或重新打开 PWA 导航到该页面为止。

您可以使用 self 对象监听 Service Worker 的全局范围内的事件:

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");
});

更新 Service Worker

当浏览器检测到控制客户端的 Service Worker 与来自服务器的新版 Service Worker 文件具有不同的字节时,Service Worker 就会进行更新。

安装成功后,新的 Service Worker 将等待激活,直到旧 Service Worker 不再控制任何客户端。此状态称为“waiting”,这是浏览器确保一次只运行一个 Service Worker 版本的方式。

刷新页面或重新打开 PWA 不会使新 Service Worker 获得控制权。用户必须关闭或离开使用当前 Service Worker 的所有标签页和窗口,然后返回以让新的 Service Worker 拥有控制权。如需了解详情,请参阅 Service Worker 生命周期

Service Worker 有效期

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

如果 Service Worker 尚未运行,则每当在其范围内发送网络请求或收到定期后台同步或推送消息等触发事件时,Service Worker 就会启动。

如果 Service Worker 处于空闲状态几秒钟,或者处于忙碌状态的时间过长,则会终止它们。此操作的执行时间因浏览器而异。如果 Service Worker 被终止,并且发生了可启动该 Service Worker 的事件,它将会重启。

功能

已注册的活跃 Service Worker 使用的线程的执行生命周期与 PWA 主线程完全不同。但在默认情况下,Service Worker 文件本身没有任何行为。它不会缓存或提供任何资源;这些就是您的代码需要执行的操作。请参阅以下章节。

Service Worker 的功能不仅仅适用于代理或处理 HTTP 请求。在此之上还可实现其他用途,例如执行后台代码、网络推送通知和处理付款。我们将在功能中讨论这些新增功能。

资源