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还是其他tab
worker.port.onmessage = function (e) {
console.log("index.html", e);
};
// 给 worker 发送消息
function handleClick() {
worker.port.postMessage({
id,
message: "from index",
});
}
接下来在 chrome 访问即可,可以通过 chrome://inspect/#workers
查看当前运行的 sharedworker
实例。
通过浏览器访问页面,给 worker 发送消息,可以看到两个 tab 都能够实时接收到消息。😋
FAQ
SharedWorker 会存活多久?
只要有一个激活的页面引用了该 worker 就会一直存活。
SharedWorker 运行不是最新的代码?
每次调用 new SharedWorker()
注册的 shared-worker.js 可能无法使用到最新的 worker 代码,可能是缓存导致的。可以在 chrome 下清空下缓存,注意时间范围选“不限”。
SharedWorker 能实现浏览器多个tab通信,当然不止 SharedWorker,其他方案例如:Storage Event,WebSocket,Broadcast Channel都可以实现,可以按实际情况选择使用。