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 实例。

Chrome SharedWorker
Chrome SharedWorker

通过浏览器访问页面,给 worker 发送消息,可以看到两个 tab 都能够实时接收到消息。😋

SharedWorker效果图
SharedWorker效果图

FAQ

SharedWorker 会存活多久?

只要有一个激活的页面引用了该 worker 就会一直存活。

SharedWorker 运行不是最新的代码?

每次调用 new SharedWorker() 注册的 shared-worker.js 可能无法使用到最新的 worker 代码,可能是缓存导致的。可以在 chrome 下清空下缓存,注意时间范围选“不限”。

清空浏览器缓存
清空浏览器缓存

SharedWorker 能实现浏览器多个tab通信,当然不止 SharedWorker,其他方案例如:Storage Event,WebSocket,Broadcast Channel都可以实现,可以按实际情况选择使用。