请解释 Shared Workers 的作用和用法。它与 Web Workers 有什么区别?

推荐答案

Shared Workers 允许多个浏览上下文(例如,不同的浏览器标签页、iframe 或窗口)共享同一个 worker 线程。它们提供了一种在多个脚本之间进行通信和共享数据的机制。与 Web Workers 不同,Web Workers 是每个脚本或页面独有的,Shared Workers 则在多个脚本之间共享。

用法:

  1. 创建 Shared Worker: 使用 new SharedWorker('worker.js') 创建,传入 worker 脚本的 URL。
  2. 连接到 Shared Worker: 每个需要使用 Shared Worker 的脚本都必须通过 port 属性获取一个 MessagePort 对象,并使用 port.start() 启动连接。
  3. 消息传递: 使用 port.postMessage() 发送消息到 worker,使用 port.onmessage 监听来自 worker 的消息。
  4. Shared Worker 脚本: Worker 脚本通过 onconnect 事件监听连接请求,并在事件处理程序中获取新的 MessagePort 对象,然后像标准 Web Worker 一样进行消息传递。

与 Web Workers 的区别:

  • 作用域: Web Workers 是每个脚本或页面独有的,Shared Workers 在多个脚本之间共享。
  • 生命周期: Web Worker 的生命周期与其创建的脚本相关联,而 Shared Worker 的生命周期与其连接的数量有关,当没有页面连接到它时,Shared Worker 会被销毁。
  • 连接: Web Worker 直接与创建它的脚本通信,而 Shared Worker 需要通过 MessagePort 对象与多个脚本进行通信。

本题详细解读

Shared Workers 的工作原理

Shared Workers 允许不同浏览上下文(例如,不同标签页、iframe 等)共享同一个 JavaScript 脚本的执行线程。这与 Web Workers 的主要区别在于,Web Workers 是每个页面或脚本独有的。

创建和连接过程:

  1. 创建 Shared Worker: 使用 new SharedWorker('worker.js') 创建一个 Shared Worker。浏览器会加载 worker.js 文件,但不会立即执行其中的代码。
  2. 首次连接: 当第一个页面调用 new SharedWorker() 时,worker 脚本的 onconnect 事件会被触发。这个事件回调函数会接收到一个 MessagePort 对象。你可以使用 event.ports[0] 或解构赋值 const [port] = event.ports 来获取这个端口。
  3. 建立连接: 每个需要与 Shared Worker 通信的脚本(包括创建它的脚本)都必须使用 worker.port.start() 来显式启动连接。 此时,SharedWorker 实例的 port 属性是一个 MessagePort 对象。
  4. 后续连接: 当其他页面或脚本调用 new SharedWorker() 并成功建立连接(port.start())时,Worker 脚本的 onconnect 事件会被再次触发,这样每个连接都有一个唯一的 MessagePort 对象用于通信。
  5. 消息传递:
    • 页面通过 port.postMessage(message) 向 Shared Worker 发送消息。
    • Shared Worker 使用 port.onmessage = function(event) { ... } 接收来自页面的消息,并通过 port.postMessage(response) 回复。
  6. Shared Worker 生命周期: Shared Worker 的生命周期取决于与其连接的页面或脚本的数量。当没有任何页面或脚本连接到 Shared Worker 时,它会被浏览器自动销毁。

Shared Worker 的代码结构

HTML/JS (index.html/index.js):

-- -------------------- ---- -------
---- ---------- ---
--------- -----
------
------
    ------------- ------ ---------------
-------
------
    ------- ----------------- ----------------
    ---- ------------------
    ------- ------------------------
-------
-------
-- -------------------- ---- -------
-- --------
----- ------ - --- --------------------------
----- --------- - ----------------------------------
----- ------- - -----------------------------------

--------------------
--------------------- - --------------- -
  ------------------- -- ------------ ---- ------- -------------------
--


--------------------------------- -- -- -
    ----- ------- - ------ ---- ------
    ---------------------------------
    ------------------- -- -------- -- ------- ----------------
---


------------------------------------
-------------------------------------------------------

Worker (worker.js):

-- -------------------- ---- -------
-- ---------
--------- - ----------- -
  ----- ---- - -----------

  -------------- - --------------- -
    -------------------- -------- -- --------- ------------
    ------------------------ -------- ---- -------- - - ------------
  --
    
    ------------------------ -- --------
  
--

Web Workers 与 Shared Workers 的主要区别

特性 Web Workers Shared Workers
作用域 每个页面或脚本独有 多个页面或脚本共享
生命周期 与创建它的脚本关联 与连接的数量关联,无连接则销毁
通信方式 直接与创建它的脚本通信 通过 MessagePort 对象与多个脚本通信
应用场景 执行单个页面内的耗时任务,避免阻塞主线程 多个页面间共享数据、状态或复杂计算
创建方式 new Worker('worker.js') new SharedWorker('worker.js')
连接方式 直接通过 worker 实例的 postMessage 方法和 onmessage 事件 通过获取 MessagePort 对象并调用 start 进行连接,使用 postMessageonmessage进行通信
纠错
反馈