SharedWorker使用总结
最近有个需求要在浏览器页签之间实现信息共享,由第三方包处理。看过人家的效果介绍,嚯哦,闪瞎我的双眼!没见识过的技术,怎么也得看一看呀🧐
介绍
SharedWorker
接口代表一种特定类型的 worker,可以从几个浏览上下文中访问,例如几个窗口、iframe 或其他 worker。它们实现一个不同于普通 worker 的接口,具有不同的全局作用域,SharedWorkerGlobalScope 。
备注: 如果要使 SharedWorker 连接到多个不同的页面,这些页面必须是
同源
的(相同的协议、host 以及端口)。
又称共享线程。之所以可以在多个浏览器页签中共享信息,是因为在页签的html中创建SharedWorker
时,如果第一个参数相同,则视为同一线程,所以只要保证创建时的第一个参数相同,就可以在多页签间共享信息。
api
下面给了一些基本的api使用。以下api的使用都基于SharedWorker
的实例对象的port属性。
创建
使用构造函数SharedWorker()
创建SharedWorker
实例。它有三个参数如下
MDN解释
举例
复制const sharedWorker = new SharedWorker('被共享的js文件url', '标识woker的名字', 可选属性对象);
自我“治愈”:
第一个参数:是被共享的js的url,要同源! 在共享线程中,我们总要做点什么。在哪里做呢?就在这个被共享的js文件中捣鼓。
第二个参数:可以标识当前的worker。在下文提到的调试
中,我们会用到。主要用来确定,这个worker是不是我们现在写的worker,万一浏览器里有其他人写的worker呢?
第三个参数: 还没有深究过,这里就不介绍了。
启用
这里先随便给个url做示例~
const sharedWorker = new SharedWorker('sharedWorker.js', 'test worker');
// 开启与共享线程的连接
sharedWorker.port.start();
MDN解释
关于start()
的使用,可以参考下文中填脑坑
的第一条。
上面的MessagePort
对象就是sharedWorker.port
。所有关于浏览器页签和共享线程的通信都是通过sharedWorker.port
来控制和管理。
关闭
和上面的启用基本一样,只不过名字换成了close
。即sharedWorker.port.close()
执行之后,就关闭了当前浏览器页签与共享线程间的连接,不再和共享线程互通消息。
消息通信
就是sharedWorker.port.postMessage(message, transferList)
.
第一个参数:当前浏览器页签想要发给共享线程的信息,可以是任意数据类型
第二个参数:暂不深究
调试
点击打开调试页面👉chrome://inspect/#workers 可以看到下面的内容
调试控制台大家可以理解为Chrome
的DevTools
,一模一样。可以在上面看到自己在共享js文件中写的console
❗️❗️❗️注意
- 单页应用的时候记得及时关闭worker,否则常驻
- 每创建一个worker,如果参数url都一样,那么会视为使用同一个共享线程,共享线程会分配一个port对象来区分不同使用者。即
SharedWorker
实例对象的port可以用来区分不同的页签。
关于共享js文件
还有一点。因为有同源限制,所以需要开一个服务器才能看到信息共享效果。可以试试VS Code
的Live Server
插件.
案例
案例准备了两个文件,一个是共享的js文件,一个是html文件。
测试效果的时候,最少在浏览器上打开两个相同的页签。无论点击哪个页签的【获取消息】,两个页签都会alert一个3出来。
共享js文件
sharedWorker.js
let number = 3
// 储存所有port
this.ports = []
onconnect = e => {
const port = e.ports[0];
!this.ports.includes(port) && this.ports.push(port)
// 监听浏览器页签发送的消息
port.onmessage = (e) => {
switch (e.data) {
case 'getData':
// 广播:给所有port发消息
broadcast(number)
break;
case 'close':
clearInvalidPort(port)
break;
default:
break;
}
}
}
function broadcast(message) {
console.log('ports', this.ports)
this.ports.forEach(port => {
// 给浏览器页签发消息
port.postMessage(message)
})
}
function clearInvalidPort(port) {
const index = this.ports.findIndex(item => item === port);
if (~index) {
this.ports.splice(index, 1);
}
}
html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="btn">获取消息</button><br/>
<button id="closeBtn">关闭sharedWorker</button>
<script>
let myWorker = new SharedWorker('./sharedWorker.js', 'test worker')
// 监听共享线程传递的消息
myWorker.port.onmessage = (e) => alert(e.data);
btn.addEventListener('click', e=> {
// 给共享线程发送消息
myWorker.port.postMessage('getData');
});
closeBtn.addEventListener('click', e=> {
// 取消该port在共享线程中的存储[广播用的]
myWorker.port.postMessage('close');
// 关闭与共享线程的连接
myWorker.port.close();
});
window.onbeforeunload = () => {
myWorker.port.postMessage('close');
myWorker.port.close();
};
</script>
</body>
</html>
填脑坑
自己在学习过程中不理解的点。
MessagePort对象一定要调用start()吗?
不一定。
- 如果给
MessagePort
对象的onmessage
属性赋值,就默认开启与共享线程的连接。 - 如果对象使用
addEventListener()
监听message
,就需要调用start()
共享js文件中的onconnect函数为什么用e.port[0]获取port对象?没有其他的获取方式了吗?
因为e.port
是只包括一个MessagePort
对象的数组。没有其他方式。
共享js文件中onconnect怎么解释?
新客户端连接的时候会触发。
具体可以看下这里
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律