Web Worker 和 Service Worker 如何提升网站性能,以及何时使用 Web Worker 和 Service Worker。
本概览介绍了 Web Worker 和 Service Worker 如何提升网站的性能,以及何时使用 Web Worker 而非 Service Worker。如需了解特定的窗口和 Service Worker 通信模式,请参阅本系列文章的其余部分。
工作人员如何改进您的网站
浏览器使用单线程(主线程)运行网页中的所有 JavaScript,并执行呈现网页和执行垃圾回收等任务。 运行过多的 JavaScript 代码可能会阻塞主线程,从而延迟浏览器执行这些任务,并导致糟糕的用户体验。
在 iOS/Android 应用开发中,可确保应用的主线程随时可响应用户事件的一种常见模式是将操作分流到其他线程。事实上,在最新版本的 Android 中,阻塞主线程的时间过长会导致应用崩溃。
在 Web 中,JavaScript 是围绕单线程的概念设计的,缺少实现像应用那样的多线程模型(例如共享内存)所需的功能。
尽管存在这些限制,但类似的模式可以在网络中实现,方法是使用工作器在后台线程中运行脚本,在不干扰主线程的情况下执行任务。工作器是在单独的线程上运行的整个 JavaScript 作用域,没有任何共享内存。
在这篇博文中,您将了解两种不同类型的 worker(Web Worker 和 Service Worker),它们的异同,以及它们在生产网站中最常见的模式。
![显示 Window 对象与 Web Worker 和 Service Worker 之间的两个链接的示意图。](https://web.developers.google.cn/static/articles/workers-overview/image/diagram-showing-links-be-3f8d21126eb87.png?authuser=8&hl=hu)
Web Worker 和 Service Worker
相似点
Web 工作器和 Service Worker 是网站可用的两种工作器。它们有一些共同点:
- 两者都在辅助线程中运行,允许 JavaScript 代码在不阻塞主线程和界面的情况下执行。
- 它们无权访问
Window
和Document
对象,因此无法直接与 DOM 进行交互,并且对浏览器 API 的访问权限有限。
不同点
可能有人认为大多数可委托给网页 worker 的操作都可以在 Service Worker 中完成,反之亦然,但它们之间有很大的区别:
- 与 Web 工作器不同,借助 Service Worker,您可以拦截网络请求(通过
fetch
事件)并在后台监听 Push API 事件(通过push
事件)。 - 一个页面可以生成多个 Web 工作器,但单个 Service Worker 可控制其注册的范围内的所有活动标签页。
- Web 工作器的生命周期与其所属的标签页紧密耦合,而 Service Worker 的生命周期则独立于它。因此,关闭正在运行 Web Worker 的标签页会终止其运行,而 Service Worker 可以继续在后台运行,即使网站未打开任何活跃标签页也是如此。
用例
这两种类型的工作器之间的差异表明了在什么情况下,一种可能想要使用其中一种:
Web 工作器的用例通常与将工作(如繁重的计算)分流到辅助线程(以免阻塞界面)相关。
![显示从 Window 对象到 Web Worker 的链接的示意图。](https://web.developers.google.cn/static/articles/workers-overview/image/diagram-showing-link-th-27e9ed5676ba6.png?authuser=8&hl=hu)
- 示例:开发视频游戏 PROXX 的团队希望让主线程尽可能腾出时间来处理用户输入和动画。为此,他们使用 Web 工作器在单独的线程上运行游戏逻辑和状态维护。
![视频游戏“PROXX”的屏幕截图。](https://web.developers.google.cn/static/articles/workers-overview/image/a-screenshot-the-videoga-d7cb8cb8a682c.png?authuser=8&hl=hu)
Service Worker 任务通常与充当网络代理、处理后台任务以及缓存和离线等任务更相关。
![视频游戏“PROXX”的屏幕截图。](https://web.developers.google.cn/static/articles/workers-overview/image/a-screenshot-the-videoga-e3257857d928d.png?authuser=8&hl=hu)
示例:在播客 PWA 中,您可能希望允许用户下载完整分集以便在离线时收听。为此,可以使用 Service Worker,特别是 Background Fetch API。这样,如果用户在下载分集期间关闭了标签页,就不必中断任务。
![播客 PWA 的屏幕截图。](https://web.developers.google.cn/static/articles/workers-overview/image/a-screenshot-a-podcast-p-910200b097c52.png?authuser=8&hl=hu)
工具和库
可以使用不同的较低级别的 API 来实现窗口和 worker 通信。幸运的是,有一些库可以抽象化此过程,适用于最常见的用例。在本部分中,我们将介绍 Comlink 和 Workbox 这两种工具,它们分别负责 Web 工作器和 Service Worker 的窗口。
![视频游戏“PROXX”的屏幕截图。](https://web.developers.google.cn/static/articles/workers-overview/image/a-screenshot-the-videoga-1d6073255f591.png?authuser=8&hl=hu)
Comlink
Comlink 是一个小型 (1.6k) RPC 库,可在构建使用 Web Worker 的网站时处理许多底层细节。它已被用于 PROXX 和 Squoosh 等网站。如需查看其动机摘要以及代码示例,请点击此处。
Workbox
Workbox 是一个热门库,可用于构建使用 Service Worker 的网站。它封装了缓存、离线、后台同步等方面的一系列最佳实践。workbox-window
模块提供了一种在 Service Worker 与页面之间交换消息的便捷方式。
后续步骤
本系列文章的其余部分重点介绍窗口和 Service Worker 的通信模式:
- 命令式缓存指南:从页面调用 Service Worker 以提前(例如在预提取场景中)缓存资源。
- 广播更新:从 Service Worker 调用页面以通知重要更新(例如,网站有新版本)。
- 双向通信:将任务委托给 Service Worker(例如下载大量内容),并让页面随时了解进度。
如需了解窗口和网络工作器通信的模式,请参阅:使用网络工作器从浏览器的主线程运行 JavaScript。