SharedWorker 是一种可以在多个标签页之间共享的 Web Worker。它可以让多个标签页共享同一个 JavaScript 实例。与普通的 Web Worker 不同,SharedWorker 可以在多个标签页之间共享,而普通的 Web Worker 则是每个标签页都有自己的 JavaScript 实例。
创建 SharedWorker
我们需要使用浏览器提供的 SharedWorker 来创建 worker 对象。
const sWorker = new SharedWorker(url, name);const sWorker = new SharedWorker(url, options);
第一个参数 url 是 worker 脚本的地址,脚本地址必须要是同源的才可以运行,第二个参数可以是字符串或者对象。如果是字符串,则代表当前创建的 SharedWorker 名称,如果是对象,分别有以下属性:
- type:一个制定所创建 worker 类型的 DOMString。可设定的值为 classic 或者 module. 若不指定,默认值为 classic.
- credentials:一个指定要用于工作程序的凭据类型的 DOMString。可设定的值为 omit,same-origin 或 include。若不指定,或者 type 设定为 classic,默认值为 omit (无需凭据)。
- name:一个指定表示 worker 范围的
SharedWorkerGlobalScope
(一个全局作用域,继承自WorkerGlobalScope
) 的标识名称的 DOMString,主要用于调试。
使用 SharedWorker
主线程与 SharedWorker 线程通过 MessagePort 建立链接,通过 MessagePort 进行通信。
如果通过
addEventListener
来接受消息,那么必须要手动调用start()
方法开启。如果通过onmessage
来监听,就不需要手动调用start()
方法。
我们先在项目根目录创建 shared-worker.js 文件,编写如下代码
const ports = [];onconnect = function (e) { const port = e.ports[0]; ports.push(port); port.onmessage = function (e) { console.log('worker接收到的消息:', e.data); ports.forEach((p) => { p.postMessage(e.data); }); };};
注意:shared worker
里面打印是在控制台看不到的,我们可以在下文的 worker inspect
打开控制台即可看到当前 worker 打印的内容。
然后在页面通过 new SharedWorker()
实例化。
const worker = new SharedWorker('worker.js', 'my worker');const id = `${+new Date()}_${Math.random()}`; // 唯一标记,用来区别收到的通知是来自当前tab还是其他tabworker.port.onmessage = function (e) { console.log('index.html', e);};// 给 worker 发送消息function handleClick() { worker.port.postMessage({ id, message: 'from index', });}
接下来在 chrome 访问即可,可以通过 chrome://inspect/#workers
查看当前运行的 sharedworker
实例。
Chrome SharedWorker
通过浏览器访问页面,给 worker 发送消息,可以看到两个 tab 都能够实时接收到消息。😋
SharedWorker 效果图
FAQ
SharedWorker 会存活多久?
只要有一个激活的页面引用了该 worker 就会一直存活。
SharedWorker 运行不是最新的代码?
每次调用 new SharedWorker()
注册的 shared-worker.js 可能无法使用到最新的 worker 代码,可能是缓存导致的。可以在 chrome 下清空下缓存,注意时间范围选“不限”。
清空浏览器缓存
SharedWorker 能实现浏览器多个 tab 通信,当然不止 SharedWorker,其他方案例如:Storage Event,WebSocket,Broadcast Channel 都可以实现,可以按实际情况选择使用。