推荐答案
Shared Workers 允许多个浏览上下文(例如,不同的浏览器标签页、iframe 或窗口)共享同一个 worker 线程。它们提供了一种在多个脚本之间进行通信和共享数据的机制。与 Web Workers 不同,Web Workers 是每个脚本或页面独有的,Shared Workers 则在多个脚本之间共享。
用法:
- 创建 Shared Worker: 使用
new SharedWorker('worker.js')
创建,传入 worker 脚本的 URL。 - 连接到 Shared Worker: 每个需要使用 Shared Worker 的脚本都必须通过
port
属性获取一个MessagePort
对象,并使用port.start()
启动连接。 - 消息传递: 使用
port.postMessage()
发送消息到 worker,使用port.onmessage
监听来自 worker 的消息。 - 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 是每个页面或脚本独有的。
创建和连接过程:
- 创建 Shared Worker: 使用
new SharedWorker('worker.js')
创建一个 Shared Worker。浏览器会加载worker.js
文件,但不会立即执行其中的代码。 - 首次连接: 当第一个页面调用
new SharedWorker()
时,worker 脚本的onconnect
事件会被触发。这个事件回调函数会接收到一个MessagePort
对象。你可以使用event.ports[0]
或解构赋值const [port] = event.ports
来获取这个端口。 - 建立连接: 每个需要与 Shared Worker 通信的脚本(包括创建它的脚本)都必须使用
worker.port.start()
来显式启动连接。 此时,SharedWorker
实例的port
属性是一个MessagePort
对象。 - 后续连接: 当其他页面或脚本调用
new SharedWorker()
并成功建立连接(port.start()
)时,Worker 脚本的onconnect
事件会被再次触发,这样每个连接都有一个唯一的MessagePort
对象用于通信。 - 消息传递:
- 页面通过
port.postMessage(message)
向 Shared Worker 发送消息。 - Shared Worker 使用
port.onmessage = function(event) { ... }
接收来自页面的消息,并通过port.postMessage(response)
回复。
- 页面通过
- 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 进行连接,使用 postMessage 和 onmessage 进行通信 |