shared worker实现多页面通信
背景
中后台项目场景中,业务人员经常为了操作方便,同一个后台系统浏览器打开多个tab页面来操作,当打开多个浏览器tab页面时,例如全局通知框、或者某定制的消息通知等业务组件,在某个页面关掉时,其他的tab页面之下是不会同步关掉的,这就影响到了业务人员使用系统的效率,此时我们需要同时关闭掉其他页面的通知框,避免重复显示,影响效率和体验。
如图:(此类全局通知框或者特殊设计的通知框等不自动关闭)
解决方案:
有localstorage、sharedworker、websocket等方案,最近组内开始有用到worker了,对于这个没用使用过的html5新特性,学习了一下,下面介绍使用sharedworker的解决方案。
worker 介绍:
Web Worker 是 HTML5 标准的一部分,这一规范定义了一套 API,它允许一段 JavaScript 程序运行在主线程之外的另外一个线程中。
这在很大程度上利用了现在不断升级的电脑计算能力:能够在同一时间平行处理两个任务,而不影响主线程ui渲染。
worker基本用法
主线程采用new
命令,调用Worker()
构造函数,新建一个 Worker 线程。
const worker = new Worker('work.js');
主线程调用worker.postMessage()
方法,向 Worker 发消息。
worker.postMessage('Hello World');
主线程通过worker.onmessage
指定监听函数,接收子线程发回来的消息。
worker.onmessage = function (event) {
console.log('Received message ' + event.data);
doSomething();
}
Worker 线程内部需要有一个监听函数,监听message
事件。
self.addEventListener('message', function (e) {
self.postMessage('You said: ' + e.data);
}, false);
通过self.postMessage给主线程发送消息。
shared worker 介绍:
当前我们用到的是shared worker,shared worker是webworker的一种,由同源的所有页面共享。 shared worker普通 Worker 区别:
1、 同一个js脚本会创建一个 sharedWorker,其他页面再使用同样的脚本创建sharedWorker,会复用已创建的 worker,这个worker由几个页面共享,顾名思义叫shared worker。
2、 sharedWorker通过port来发送和接收消息
用法:
1.调试方法:
如图,打开chrome://inspect 选择shared workers,会打开一个devtool,worker文件中的网络请求,打印都在这个里边进行查看
2.spa项目中应用
安装worker-loader
module.exports = {
chainWebpack: config =>
{
config.module
.rule('worker')
.test(/\.worker\.js$/)
.use('worker')
.loader('worker-loader')
.tap(() => ({ worker: 'SharedWorker' }))
}
}
2.向多个页面发布消息
注册worker时,将每个页面的worker缓存起来,向所有页面广播消息时,遍历ports,逐个去发消息,当页面关闭时,广播关闭worker的消息,清除缓存
// 页面 window.onbeforeunload = () => { myWorker.port.postMessage('CLOSE'); };
// 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);
if (e.data === 'CLOSE'){
const index = ports.findIndex(p => p === port);
portPool.splice(index, 1); }
}
}
function boardcast(message) {
portPool.forEach(port => {
port.portMessage(port);
})
}
更多应用场景
1.webworker单开线程跑计算量大、耗时的任务,不影响主线程ui渲染
2.页面之间登录状态通知(如:github的登录状态)
3.后台spa项目中,多个浏览器tab页面数据通信 等。。。
参考:
developer.mozilla.org/zh-CN/docs/…