JavaScript 中的 Worker 有什么作用?
主题
JavaScript
TL;DR
JavaScript 中的 Worker 是后台线程,允许您与主执行线程并行运行脚本,而不会阻塞或干扰用户界面。 它们的主要特点包括:
- 并行处理:Worker 在与主线程不同的线程中运行,允许您的网页在 worker 执行其任务时保持对用户交互的响应。 这对于将 CPU 密集型工作从主线程中移出并摆脱 JavaScript 单线程的特性非常有用。
 - 通信:使用 
postMessage()和onmessage/'message'事件进行消息传递。 - 访问 Web API:Worker 可以访问各种 Web API,包括 
fetch()、IndexedDB 和 Web Storage,允许它们独立执行数据获取和持久化数据等任务。 - 无法访问 DOM:Worker 无法直接操作 DOM,因此无法与 UI 交互,确保它们不会意外干扰主线程的操作。
 
JavaScript 中有三种主要的 worker 类型:
- Web worker / 专用 worker
- 在后台线程中运行脚本,与主 UI 线程分开。
 - 适用于 CPU 密集型任务,如数据处理、计算等。
 - 无法直接访问或操作 DOM。
 
 - Service worker
- 充当网络代理,处理应用程序和网络之间的请求。
 - 启用离线功能、缓存和推送通知。
 - 独立于网页运行,即使网页已关闭。
 
 - 共享 worker
- 只要它们在同一域中,就可以由在不同窗口或框架中运行的多个脚本共享。
 - 脚本通过发送和接收消息与共享 worker 通信。
 - 适用于协调网页不同部分的任务。
 
 
JavaScript 中的 Worker
JavaScript 中的 Worker 是一种在后台线程中运行脚本的方式,与网页的主执行线程分开。 这允许将长时间运行或计算密集型任务从主线程中卸载,防止用户界面变得无响应或卡顿。
Web worker / 专用 worker
- 在与主 UI 线程分开的后台线程中运行脚本。
 - 专为 CPU 密集型任务而设计,如数据处理、数学计算等。 通常是非异步工作。
 - 出于安全原因,无法直接访问 DOM 或其他主线程资源。
 - 通过异步消息传递进行与主线程的通信 – 
postMessage()和onmessage/'message'。 - 当主脚本被卸载或显式终止时终止。
 
Web worker 可用于:
- 图像/视频处理
 - 数据压缩
 - 复杂数学
 
创建一个 web worker
要创建一个 web worker,您需要一个单独的 JavaScript 文件,其中包含 worker 的代码。 这是一个例子:
main.js (主脚本)
// 检查浏览器是否支持 workerif (window.Worker) {// 创建一个新的 Workerconst myWorker = new Worker('worker.js');// 向 worker 发送消息myWorker.postMessage('Hello, Worker!');// 监听来自 worker 的消息myWorker.onmessage = function (event) {console.log('来自 Worker 的消息:', event.data);};// 错误处理myWorker.onerror = function (error) {console.error('来自 Worker 的错误:', error);};}
worker.js (worker 脚本)
// 监听来自主脚本的消息onmessage = function (event) {console.log('来自主脚本的消息:', event.data);// 执行一个任务(例如,一些计算)const result = event.data + ' - 由 Worker 处理';// 将结果发回给主脚本postMessage(result);};
在这个例子中:
main.js使用Worker构造函数创建一个 worker,并指定worker.js作为在 worker 线程中运行的脚本。- 它使用 
postMessage()向 worker 发送消息。 - worker 脚本 (
worker.js) 使用onmessage监听来自主脚本的消息。 - 处理完消息后,worker 使用 
postMessage()将消息发回给主脚本。 - 主脚本在 
Worker实例上使用onmessage监听来自 worker 的消息。 
Service workers
- 充当 Web 应用程序、浏览器和网络之间的网络代理。
 - 可以拦截和处理网络请求,缓存资源。
 - 启用离线功能和推送通知。
 - 具有由浏览器管理的生命周期(安装、激活、更新)。
 - 出于安全考虑,无法访问 DOM 和主线程资源。
 
Service workers 可以用于:
- 缓存
 - 离线支持
 - 请求处理
 - 后台同步
 
创建 service worker
main.js (主脚本)
if ('serviceWorker' in navigator) {navigator.serviceWorker.register('/service-worker.js').then(function (registration) {console.log('Service Worker registered:', registration);}).catch(function (err) {console.log('Service Worker registration failed:', err);});}
service-worker.js (service worker 脚本)
self.addEventListener('fetch', function (event) {event.respondWith(caches.match(event.request).then(function (response) {// return cached response if availableif (response) {return response;}// Otherwise, fetch from networkreturn fetch(event.request);}),);});
在这个例子中:
- 主脚本在 
/service-worker.js注册一个 service worker - service worker 监听 
fetch()事件,该事件在浏览器发出网络请求时触发 - service worker 首先使用 
caches.match(event.request)检查请求的资源是否已缓存 - 如果已缓存,则返回缓存的响应。 否则,它使用 
fetch(event.request)从网络获取资源 
奖励:共享 worker
- 范围:可以从不同窗口/标签页/iframe 中的多个脚本访问
 - 数据共享:允许通过消息传递接口在浏览器上下文之间共享数据
 - 浏览器支持:支持有限,尤其在 Android 浏览器上不可用
 
共享 worker 的用例:
- 跨多个窗口共享状态。
 
奖励:Worklets
Worklet 接口是 Web Workers 的轻量级版本,它使开发人员可以访问渲染管道的低级部分。 使用 Worklets,您可以运行 JavaScript 和 WebAssembly 代码来执行图形渲染或音频处理,其中需要高性能。
您不需要了解 worklets,因此不会详细介绍。 在 MDN 上阅读有关 worklets 的更多信息。
考虑事项和限制
- 同源策略:Workers 必须遵守同源策略,这意味着创建 worker 的脚本和 worker 脚本本身必须来自同一源
 - 无 DOM 访问:Workers 无法直接访问 DOM。 它们可以通过消息与主线程通信
 - 性能:创建和管理 workers 会产生开销。 它们应该谨慎用于真正受益于并行执行的任务
 - 错误处理:应建立适当的错误处理机制来处理 worker 脚本中的任何问题