Web Worker 和 Service Worker 如何提高网站的性能,以及何时使用 Web Worker 而不是 Service Worker。
本概览介绍了 Web Worker 和 Service Worker 如何提升网站性能,以及何时应使用 Web Worker 而不是 Service Worker。如需了解窗口和服务工作器通信的具体模式,请查看本系列的其余部分。
工作人员如何改进您的网站
浏览器使用单个线程(即主线程)来运行网页中的所有 JavaScript,以及执行呈现网页和执行垃圾回收等任务。运行过多的 JavaScript 代码可能会阻塞主线程,导致浏览器延迟执行这些任务,进而导致用户体验不佳。
在 iOS/Android 应用开发中,确保应用的主线程保持空闲状态以响应用户事件的常见模式是将操作分流到其他线程。事实上,在最新版本的 Android 中,如果主线程被阻塞的时间过长,会导致应用崩溃。
在 Web 上,JavaScript 是围绕单线程概念设计的,缺乏实现应用所具有的多线程模型(例如共享内存)所需的功能。
尽管存在这些限制,但仍可在 Web 中使用工作线程在后台线程中运行脚本,从而实现类似模式,使脚本能够执行任务而不干扰主线程。Worker 是在单独线程上运行的完整 JavaScript 作用域,不使用任何共享内存。
在这篇博文中,您将了解两种不同类型的工作器(Web 工作器和服务工作器)、它们的异同,以及在正式版网站中使用它们的最常见模式。

Web 工作器和 Service Worker
相似之处
Web worker 和 service worker 是网站可用的两种类型的 worker。它们有一些共同点:
- 两者都在辅助线程中运行,因此 JavaScript 代码可以执行,而不会阻塞主线程和界面。
- 它们无法访问
Window
和Document
对象,因此无法直接与 DOM 互动,并且对浏览器 API 的访问权限有限。
不同之处
您可能会认为,可以委托给 Web Worker 的大多数任务都可以在 Service Worker 中完成,反之亦然,但两者之间存在重要区别:
- 与 Web Worker 不同,Service Worker 允许您拦截网络请求(通过
fetch
事件),并在后台监听 Push API 事件(通过push
事件)。 - 一个网页可以派生出多个 Web Worker,但一个 Service Worker 会控制在注册时所用的作用域下的所有有效标签页。
- Web Worker 的生命周期与其所属的标签页紧密相关,而 Service Worker 的生命周期则不受此限制。因此,关闭运行 Web Worker 的标签页会终止该 Web Worker,而 Service Worker 即使在网站没有任何打开的有效标签页的情况下,也可以继续在后台运行。
使用场景
这两种类型的工作器之间的差异表明,在哪些情况下可能需要使用其中一种:
Web Worker 的使用场景通常与将工作(例如繁重的计算任务)分流到辅助线程相关,以避免阻塞界面。

- 示例:开发视频游戏 PROXX 的团队希望尽可能释放主线程,以便处理用户输入和动画。为此,他们使用 Web Worker 在单独的线程上运行游戏逻辑和状态维护。

Service worker 任务通常更侧重于充当网络代理、处理后台任务以及缓存和离线等。

示例:在播客 PWA 中,开发者可能希望允许用户下载完整的分集,以便在离线时收听。为此,可以使用服务工作线程,尤其是 Background Fetch API。这样一来,如果用户在下载分集时关闭标签页,任务就不必中断。

工具和库
可以使用不同的较低级别 API 来实现窗口和工作器通信。幸运的是,有一些库可以抽象化此流程,并处理最常见的用例。在本部分中,我们将介绍其中两个分别负责窗口到 Web 工作器和窗口到服务工作器的工具:Comlink 和 Workbox。

Comlink
Comlink 是一个小型 (1.6k) RPC 库,可在构建使用 Web Worker 的网站时处理许多底层细节。它已用于 PROXX 和 Squoosh 等网站。如需查看其动机和代码示例的摘要,请点击此处。
Workbox
Workbox 是一个用于构建使用 service worker 的网站的热门库。它围绕缓存、离线、后台同步等内容封装了一组最佳实践。workbox-window
模块提供了一种在服务工作线程和网页之间交换消息的便捷方式。
后续步骤
本系列文章的其余部分将重点介绍窗口和服务工作器通信的模式:
- 命令式缓存指南:从网页调用 Service Worker 以提前缓存资源(例如在预提取场景中)。
- 广播更新:从服务工作线程调用网页,以告知重要更新(例如,有新版网站可用)。
- 双向通信:将任务(例如大型下载)委托给服务工作线程,并让网页随时了解进度。
如需了解窗口和 Web 工作器通信模式,请参阅:使用 Web 工作器在浏览器的主线程之外运行 JavaScript。