JavaScript中SharedWorker实现多页面通信的实例详解

作者:拾光时间:2026-10-25 01:26:38浏览:631

本文详解如何利用SharedWorker实现同源页面间的高效通信。通过对比localStorage方案,阐述SharedWorker复用实例及port消息机制。重点讲解页面与Worker的消息交互、调试方法,以及多页面广播和无效Port清理策略,提供完整代码示例与最佳实践。

在GitHub上浏览未登录页面并完成登录后,切换至其他页面时会看到相应的状态提示。

SharedWorker简介

实现这一功能的一种常见思路是利用localStorage:在登录页面修改其状态,其他页面在显示时读取最新状态并展示提示。


// 登录的页面
localStorage.setItem('login', true);

// 其他页面
document.addEventListener("visibilitychange", function() {
	if (localStorage.setItem('login') === 'true') {
		alert('你已登录,请刷新页面');
	}
}

然而,GitHub并未采用此方式,localStorage中也无相关字段。经排查发现,其实际使用了SharedWorker来实现该功能。

SharedWorker简介

SharedWorker简介

SharedWorker是Web Worker的一种变体,允许所有同源页面共享同一个Worker实例。与普通Worker类似,只需传入JavaScript文件的URL即可注册一个SharedWorker实例。


let myWorker = new SharedWorker('worker.js');

与普通Worker不同,SharedWorker具有以下特点: 1. 相同的JS URL只会创建一个SharedWorker实例,后续相同URL的请求将复用该实例,实现多页面共享。 2. 页面与SharedWorker之间通过port(端口)来发送和接收消息。

接下来,我们将具体探讨页面与Worker之间如何发送和接收消息。

messagePort机制

假设存在两个JS文件:运行在页面中的page.js和运行在Worker中的worker.js。在page.js中注册SharedWorker的代码如下:


// page.js
let myWorker = new SharedWorker('worker.js');
// page通过worker port发送消息
myWorker.port.postMessage('哼哼');
// page通过worker port接收消息
myWorker.port.onmessage = (e) => console.log(e.data);

// worker.js
onconnect= function(e) {
	const port = e.ports[0];
	port.postMessage('哈嘿');
	port.onmessage = (e) => {
		console.log(e.data);
	}
}

调试SharedWorker

在上述示例中,若Worker中使用console.log打印来自页面的消息,可通过浏览器地址栏输入chrome://inspect,在侧边栏选中Shared Workers查看当前运行的所有Worker。点击Inspect可打开开发者工具,从而查看输出的日志。

SharedWorker简介

示例中Worker名称显示为untitled,这是因为SharedWorker构造函数支持传入第二个参数作为名称。


let myWorker = new SharedWorker('worker.js', 'awesome worker');

多页面消息广播

回到文章开头的例子,前文实现了页面与Worker间的通信。若需让Worker向多个页面发送消息,可将port缓存起来,构建一个port池(port pool)。当需要向所有页面广播消息时,遍历该池并发送消息即可。


// worker js
const portPool = [];
onconnect= function(e) {
	const port = e.ports[0];
	// 在connect时将 port添加到 portPool中
	portPool.push(port);
	port.postMessage('哈嘿');
	port.onmessage = (e) => {
		console.log(e.data);
	}
}

function boardcast(message) {
	portPool.forEach(port => {
		port.portMessage(port);
	})
}

通过上述方式,我们基本实现了向多个页面广播消息的功能。

清除无效Port

上述实现存在一个问题:页面关闭后,portPool中的port不会自动清除,导致内存浪费。因此,可在页面关闭前通知SharedWorker即将关闭,由Worker将无效的messagePort从portPool中移除。


// 页面
window.onbeforeunload = () => {
  myWorker.port.postMessage('TO BE CLOSED');
};

// worker.js
const portPool = [];
onconnect = function(e) {
  var port = e.ports[0];
  portPool.push(port);
  port.onmessage = function(e) {
    console.log(e);
    if (e.data === 'TO BE CLOSED') {
      const index = ports.findIndex(p => p === port);
      portPool.splice(index, 1);
    }
    var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
    port.postMessage(workerResult);
  }
}

function boardcast(message) {
	portPool.forEach(port => {
		port.portMessage(port);
	})
}

至此,我们实现了一个简单的多页面广播SharedWorker。例如,可用于广播当前时间。


setInterval(() => boardcast(Date.now()), 1000);

参考资料

https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker/SharedWorker https://github.com/mdn/simple-shared-worker

本文介绍了JavaScript中SharedWorker实现多页面通信的完整过程。更多相关JS SharedWorker多页面通信内容,可搜索本站历史文章或继续浏览后续相关文章。

作者最新文章