Skip to content

Main Thread 可以使用 new SharedWorker() 连接到指定 sharedWorker

而在 Shared Worker Thread 中,顶级 self 对象指向 SharedWorkerGlobalScope,即共享 worker 全局作用域

3-1.Main Thread

创建 SharedWorker 与 创建 Worker 的方式类似,唯一要注意的是:

  1. SharedWorker 依赖端口 port 通信;

  2. 只有调用 port.start() 后,才能监听到 message 事件。

js
// Main Thread
const sharedWorker = new SharedWorker('./sharedWorker.js')

sharedWorker.port.postMessage('Main Thread')

sharedWorker.port.addEventListener('message', (e) => {
  console.log(e.data)
})

// 开启端口之后 端口才能监听到message事件
sharedWorker.port.start()

3-2.Shared Worker Thread

SharedWorkerGlobalScope 本身不支持 postMessage

需要先监听 connect 事件连接到端口 port,然后再利用 port 通信。

js
// Shared Worker Thread
self.addEventListener('connect', e => {
  const port = e.ports[0]
  port.postMessage('Post Message from Shared Worker')

  port.addEventListener('message', event => {
    console.log('Shared Worker Thread', event.data)
  })

  port.start()
})

3-3.调试

SharedWorkerGlobalScope 的消息不会在默认的 console 控制台打印。

为了调试这部分代码的话,可以访问chrome://inspect

另外,MDN 上的Simple Shared Worker也可以作为使用参考。

3-4.跨Tab数据通信

据笔者所知,Tab 数据通信有两种方式:

  1. 可以利用 window.open 方法产生的opener 数据通信;

  2. 本节的 SharedWorker

受到Redux SharedWorker的启发,可以将 SharedWorker 封装成公共函数,在各自数据通信的逻辑中调用即可。

假设有 Main ThreadIframe ThreadShared Worker Thread

js
// Main Thread
import getSharedWorker from './worker.js'

const worker = getSharedWorker()

worker.port.postMessage('Post Message from Main Thread')

worker.port.addEventListener('message', e => {
  console.log(e.data)
})

worker.port.start()
js
// Iframe Thread
import getSharedWorker from './worker.js'

const worker = getSharedWorker()

worker.port.postMessage('Post Message from Iframe Thread')

worker.port.addEventListener('message', e => {
  console.log(e.data)
})

worker.port.start()
js
// Shared Worker Thread
// 为了保证响应式 可以将所有port存储到数组中,这样任一port变化时,都能作出反应。
const customrWorker = `
const workerList = []
self.addEventListener('connect', e => {
  workerList.push(e.ports[0])
  workerList.forEach(worker => {
    worker.addEventListener('message', event => {
      console.log(event.data)
    })
    worker.start()
  })
})
`

export default function () {
  return new SharedWorker(`data:application/javascript,${encodeURIComponent(customrWorker)}`, {
    // type: 'module',
    name: 'REDUX_SHARED_WORKER'
  })
}