Service Worker能否直接向Shared Worker客户端调用postMessage()?
在 Service Worker 中,Client 接口提供了 postMessage() 方法用于和不同类型的客户端通信,客户端类型包括 "window"、"worker" 和 "sharedworker"。
对于 "window" 类型的客户端,调用 postMessage() 发送的消息,会触发 navigator.serviceWorker.controller 上的消息事件,示例代码如下:
const windowClients = await clients.matchAll({ type: "window" }); windowClients[0].postMessage('Send this message to window.navigator.serviceWorker.controller');
但针对 "sharedworker" 类型的客户端,早期环境里 Shared Worker 内部并没有 navigator.serviceWorker 对象(不过目前草案规范已更新,Safari 已支持该属性)。如果在 Service Worker 中执行以下代码:
const sharedWorkerClients = await clients.matchAll({ type: "sharedworker" }); sharedWorkerClients[0].postMessage('Send this message to ???');
核心问题
消息事件会在 Shared Worker 中的哪个位置被分发?或者 postMessage() 在这里是无操作的?
(注:已有一些变通方案,比如让页面把 SharedWorker#port 传递给 Service Worker,但这里想了解是否有直接发送消息的方式。)
解答
当你在 Service Worker 中调用 sharedworker 类型 Client 的 postMessage() 时,消息事件会直接分发到 Shared Worker 的全局作用域上,你可以在 Shared Worker 内部通过监听 message 事件来接收:
// Shared Worker 内部代码 self.addEventListener('message', (event) => { console.log('收到来自 Service Worker 的消息:', event.data); });
需要注意的细节:
- 只有当 Shared Worker 所在环境支持在其内部访问
navigator.serviceWorker时,这种直接通信的方式才能正常工作(目前 Safari 已支持,其他现代浏览器也在逐步跟进)。 - 如果环境不支持该特性,此时调用
postMessage()会是无操作,消息无法被接收,这种情况下就需要使用你提到的变通方案:让关联的页面将SharedWorker#port传递给 Service Worker,再通过端口进行通信。
内容的提问来源于stack exchange,提问作者Ben Dean
相关产品推荐
相关产品推荐

