工作器概览

Web Worker 和 Service Worker 如何提升网站的性能,以及何时使用 Web Worker 而非 Service Worker。

Andrew Guan
Andrew Guan
Demián Renzulli
Demián Renzulli

本概览介绍了 Web Worker 和 Service Worker 如何提升网站性能,以及何时使用 Web Worker 何时使用 Service Worker。如需了解窗口和服务工件通信的具体模式,请参阅本系列文章的其余部分。

员工如何改进您的网站

浏览器使用单个线程(主线程)来运行网页中的所有 JavaScript,以及执行呈现网页和执行垃圾回收等任务。运行过多的 JavaScript 代码可能会阻塞主线程,导致浏览器延迟执行这些任务,进而导致用户体验不佳。

在 iOS/Android 应用开发中,为了确保应用的主线程始终可以自由响应用户事件,常见的做法是将操作分流到其他线程。事实上,在最新版 Android 中,主线程阻塞时间过长会导致应用崩溃

在 Web 上,JavaScript 的设计基于单线程的概念,缺少实现应用所具有的多线程模型(例如共享内存)所需的功能。

尽管存在这些限制,但您也可以在 Web 中通过使用 worker 在后台线程中运行脚本来实现类似的模式,从而让 worker 能够在不干扰主线程的情况下执行任务。工作器是运行在单独线程上的整个 JavaScript 作用域,没有任何共享内存。

在本文中,您将了解两种不同类型的工作器(Web 工作器和服务器工作器),它们之间的相似之处和不同之处,以及在正式版网站中使用它们的最常见模式。

显示 Window 对象与 Web Worker 和 Service Worker 之间的两个链接的示意图。

网络工作器和 Service Worker

相似之处

网站工作器服务工作器是网站可用的两种工作器。它们有一些共同点:

  • 这两种任务均在辅助线程中运行,这样 JavaScript 代码便可在执行时不会阻塞主线程和界面。
  • 它们无法访问 WindowDocument 对象,因此无法直接与 DOM 交互,并且对浏览器 API 的访问权限有限。

不同之处

您可能会认为,可委托给 Web Worker 的大多数工作都可以在 Service Worker 中完成,反之亦然,但它们之间存在一些重要的区别:

  • 与 Web 工作器不同,借助服务工件,您可以拦截网络请求(通过 fetch 事件),并在后台监听 Push API 事件(通过 push 事件)。
  • 网页可以生成多个 Web Worker,但单个 Service Worker 会控制其注册的作用域下的所有活跃标签页。
  • 网页工作器的生命周期与其所属的标签页紧密相关联,而服务工作器的生命周期与之无关。因此,关闭正在运行 Web Worker 的标签页会终止该 worker,而 Service Worker 可以在后台继续运行,即使网站没有打开任何活跃标签页也是如此。

使用场景

这两种类型的工作器之间的差异表明,在哪些情况下您可能需要使用哪种工作器:

Web Worker 的用例通常与将工作(例如大量计算)分流到辅助线程有关,以避免阻塞界面。

显示从 Window 对象到 Web Worker 的链接的示意图。
  • 示例:开发视频游戏 PROXX 的团队希望尽可能让主线程空闲下来,以处理用户输入和动画。为此,他们使用了 Web Worker 在单独的线程中运行游戏逻辑和状态维护。
游戏 PROXX 的屏幕截图。

服务工件任务通常与充当网络代理、处理后台任务以及缓存和离线等方面更相关。

游戏 PROXX 的屏幕截图。

示例:在播客 PWA 中,您可能希望允许用户下载完整分集,以便在离线状态下收听。为此,您可以使用服务工件,尤其是 Background Fetch API。这样一来,如果用户在分集下载期间关闭标签页,则无需中断任务。

播客 PWA 的屏幕截图。
界面会更新以指示下载进度(左)。得益于服务工件,在所有标签页关闭后,操作可以继续运行(右)。

工具和库

您可以使用不同的较低级别 API 实现窗口和 worker 通信。幸运的是,有一些库可以抽象化此过程,从而处理最常见的用例。在本部分,我们将介绍其中两个分别负责处理窗口与 Web Worker 和 Service Worker 通信的库:ComlinkWorkbox

游戏 PROXX 的屏幕截图。

Comlink 是一个小型(1.6k)RPC 库,可在构建使用 Web Worker 的网站时处理许多底层细节。它已在 PROXXSquoosh 等网站中使用。如需简要了解其动机和代码示例,请点击此处

Workbox

Workbox 是一个常用的库,用于构建使用服务工件的网站。它封装了一组围绕缓存、离线、后台同步等内容的最佳实践。workbox-window 模块提供了一种在服务工件和网页之间交换消息的便捷方式。

后续步骤

本系列文章的其余部分将重点介绍窗口和服务工件通信的模式:

  • 命令式缓存指南:从网页调用 Service Worker 以提前缓存资源(例如在预加载场景中)。
  • 广播更新:从服务工件调用网页,以便告知重要更新(例如,网站有新版本可用)。
  • 双向通信:将任务委托给服务工件(例如大量下载),并让页面及时了解进度。

如需了解窗口和 Web 工作器通信模式,请参阅:使用 Web 工作器在浏览器的主线程之外运行 JavaScript