JavaScript 中的 Worker 有什么作用?
主题
JavaScript
在GitHub上编辑
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 脚本中的任何问题