用户希望应用在网络连接速度较慢或不稳定时,甚至在离线状态下也能可靠地启动。他们希望自己最近互动过的内容(例如媒体轨道或机票和行程)可供使用。 如果请求无法实现,他们希望应用告知他们,而不是默默失败或崩溃。而且他们希望这一切都能快速实现。正如毫秒级优化带来百万级收益中所述,即使加载时间只缩短 0.1 秒,转化率也可提高 10% 之多。借助服务工作器,您的渐进式 Web 应用 (PWA) 可以满足用户的期望。

当应用请求服务工作线程范围内的资源时,即使在用户离线的情况下,服务工作线程也会拦截该请求并充当网络代理。然后,它可以决定是使用 Cache Storage API 从缓存中提供资源,还是从网络中提供资源(就像没有有效的 service worker 一样),或者从本地算法创建资源。这样一来,即使应用处于离线状态,您也能提供与平台应用一样的高品质体验。
注册 Service Worker
在 Service Worker 控制网页之前,必须先为 PWA 注册该 Service Worker。这意味着,当用户首次打开您的 PWA 时,其所有网络请求都会直接发送到您的服务器,因为 Service Worker 尚未控制您的网页。
在检查浏览器是否支持 Service Worker API 后,您的 PWA 可以注册服务工作线程。加载后,服务工作线程会在 PWA 和网络之间设置自身,拦截请求并提供相应的响应。
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register("/serviceworker.js");
}
验证是否已注册 Service Worker
如需验证服务工作线程是否已注册,请使用您喜爱的浏览器中的开发者工具。
在 Firefox 和基于 Chromium 的浏览器(Microsoft Edge、Google Chrome 或 Samsung Internet)中:
- 打开开发者工具,然后点击应用标签页。
- 在左侧窗格中,选择 Service Worker。
- 检查服务工作线程的脚本网址是否显示为“已激活”状态。(如需了解详情,请参阅生命周期)。在 Firefox 上,状态可以是“正在运行”或“已停止”。
在 Safari 中:
- 依次点击开发 > 服务工作线程。
- 检查此菜单中是否包含当前来源的条目。点击该条目会打开一个检查器,用于检查 service worker 的上下文。

范围
服务工作器所在的文件夹决定了其作用域。位于 example.com/my-pwa/sw.js
的服务工作线程可以控制 my-pwa 路径或其下的任何导航,例如 example.com/my-pwa/demos/
。服务工作线程只能控制其作用域内的项目(网页、工作线程,统称为“客户端”)。
此范围适用于浏览器标签页和 PWA 窗口。
每个作用域只允许有一个服务工作线程。当服务工作线程处于活动状态并运行时,无论内存中有多少个客户端(PWA 窗口或浏览器标签页),通常只有一个实例可用。
Safari 具有更复杂的范围管理功能(称为“分区”),这会影响范围与跨网域 iframe 的搭配使用方式。如需详细了解 WebKit 的实现,请参阅其博文。
Lifecycle
Service Worker 的生命周期决定了它们的安装方式,与 PWA 安装分开。
Service Worker 的生命周期从注册 Service Worker 开始。然后,浏览器会尝试下载并解析 Service Worker 文件。如果解析成功,则会触发服务工作线程的 install
事件。install
事件仅触发一次。
即使在用户未安装 PWA 的情况下,Service Worker 的安装也会在后台静默进行,无需用户授予权限。即使在不支持 PWA 安装的平台(例如桌面设备上的 Safari 和 Firefox)上,Service Worker API 也可用。
安装后,服务工作器需要先激活,然后才能控制其客户端(包括您的 PWA)。当 service worker 准备好控制其客户端时,会触发 activate
事件。不过,默认情况下,已激活的 Service Worker 无法管理注册它的网页,除非您下次通过重新加载网页或重新打开 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");
});
更新服务工作线程
当浏览器检测到控制客户端的服务工作线程与服务器中的新版服务工作线程文件存在字节差异时,服务工作线程会进行更新。
成功安装后,新的服务工作器会等待激活,直到旧的服务工作器不再控制任何客户端。此状态称为“等待”,浏览器通过此状态确保每次只运行一个版本的 Service Worker。
刷新页面或重新打开 PWA 不会使新的 Service Worker 接管控制权。用户必须关闭或离开使用当前服务工作线程的所有标签页和窗口,然后返回以使新的服务工作线程获得控制权。如需了解详情,请参阅服务工作线程生命周期。
Service Worker 生命周期
已安装并注册的服务工作线程可以管理其作用域内的所有网络请求。它在自己的线程上运行,由浏览器控制其激活和终止,因此即使在 PWA 打开之前或关闭之后,它也能正常运行。Service worker 在自己的线程上运行,但内存中的状态可能不会在 Service worker 的运行之间保持不变,因此请确保您希望在每次运行时重复使用的任何内容都存储在 IndexedDB 或其他永久性存储空间中。
如果服务工作线程尚未运行,则每当在其作用域内发送网络请求时,或者每当它收到触发事件(例如定期后台同步或推送消息)时,服务工作线程都会启动。
如果服务工作线程闲置了几秒钟,或者忙碌了太长时间,就会被终止。此过程的时间因浏览器而异。如果服务工作线程已终止,并且发生了会启动它的事件,则该服务工作线程会重新启动。
功能
已注册且处于活动状态的服务工作线程使用的线程与 PWA 的主线程具有完全不同的执行生命周期。不过,默认情况下,服务工作线程文件本身没有任何行为。它不会缓存或提供任何资源;这些是您的代码需要执行的操作。您将在后续章节中了解具体方法。
Service worker 的功能不仅限于代理或传送 HTTP 请求。除此之外,还有其他功能可用于其他用途,例如后台代码执行、Web 推送通知和处理付款。我们将在功能中讨论这些新增功能。