实现多页签通讯的几种方法:
- websocket协议
- localstorage、cookie
- SharedWorker(HTML5新特性)
websocket协议:
- webSoket用来实现双向通信,客户端和服务端实时通信。
- webSoket优点和缺点:
-
- 优点:对于前端来说,使用简单,功能灵活,如果部署了webSocket服务器,可以实现实时通信。
-
- 缺点:需要服务端技术的支持,如果websocket数据量比较大的话,会严重消耗服务器的资源。
websocket服务器端搭建
//初始化一个node项目:node init,一路确认就可以,文件夹会自动创建一个package.json文件
// 下载ws文件 npm i -save ws
//获得WebSocketServerr类型
var WebSocketServer = require('ws').Server;
//创建WebSocketServer对象实例,监听指定端口
var wss = new WebSocketServer({ port:8080 });
//创建保存所有已连接到服务器的客户端对象的数组
var clients=[];
//为服务器添加connection事件监听,当有客户端连接到服务端时,立刻将客户端对象保存进数组中
wss.on('connection', function (client) {
console.log("一个客户端连接到服务器")
if(clients.indexOf(client)===-1){//如果是首次连接
clients.push(client) //就将当前连接保存到数组备用
console.log("有"+clients.length+"客户端在线")
//为每个client对象绑定message事件,当某个客户端发来消息时,自动触发
client.on('message',function(msg){
console.log('收到消息'+msg)
//遍历clients数组中每个其他客户端对象,并发送消息给其他客户端
for(var c of clients){
if(c!=client){//把消息发给别人
c.send(msg);
}
}
})
}
})
发送信息的标签页
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!-- 这个页面是用来发送信息的 -->
<input type="text" id="msg">
<button id="send">发送</button>
<script>
//建立到服务端webSoket连接
var ws=new WebSocket("ws://localhost:8080")
send.onclick=function(){
if(msg.value.trim()!=''){//如果msg输入框内容不是空的
ws.send(msg.value.trim()) //将msg输入框中的内容发送给服务器
}
}
</script>
</body>
</html>
接收信息的标签页
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!-- 这个标签页是用来接收信息的 -->
<h1 >收到的消息:<p id="recMsg"></p></h1>
<script>
//建立到服务端webSoket连接
var ws=new WebSocket("ws://localhost:8080")
//当连接被打开时,注册接收消息的处理函数
ws.onopen=function(event) {
//当有消息发过来时,就将消息放到显示元素上
ws.onmessage=function(event) {
recMsg.innerHTML=event.data;
}
}
</script>
</body>
</html>
localstorage、cookie:
- localstorage是浏览器多个标签共用的存储空间,所以可以用来实现多标签之间的通信(session是会话级的存储空间,每个标签页都是单独的)
- 直接在window对象上添加事件监听
// 方法一
window.onstorage = (e) => {console.log(e)}
// 方法二
window.addEventListener('storage', (e) => console.log(e))
- onstorage以及storage事件,针对都是非当前页面对localStorage进行修改时才会触发,当前页面修改localStorage不会触发监听函数。
- 在对原有的数据的值进行修改时才会触发,比如原本已经有一个key会a值为b的localStorage,你再执行:localStorage.setItem(‘a’, ‘b’)代码,同样是不会触发监听函数的(不修改不触发监听)。
webworker:
- JavaScript是单线程的,但是浏览器是拥有多个线程,如:gui渲染线程、JS引擎线程、事件触发线程、异步http请求线程。
- webworker作为浏览器的一个新特性,可以提供一个额外的线程来执行一些js代码,并且不会影响到浏览器用户界面。
- 应用场景:比如页面中包含耗时较大的算法代码时,就会阻塞线程影响浏览器渲染等等。这时候就可把耗时代码,放到webworker(另一个线程)中执行。
注意,这种多线程能力不是JavaScript语言原生具有的,而是浏览器宿主环境提供的。 - 普通的webworker直接使用new Worker()即可创建,这种webworker是当前页面专有的。然后还有种共享worker(SharedWorker),这种是可以多个标签页、iframe共同使用的,接下来介绍如何使用SharedWorker实现标签页之间的通信。
SharedWorker(HTML5新特性):
- SharedWorker可以被多个window共同使用,但必须保证这些标签页都是同源的(相同的协议,主机和端口号)
- 首先新建一个js文件worker.js,具体代码如下:
// sharedWorker所要用到的js文件,不必打包到项目中,直接放到服务器即可
let data = ''
onconnect = function (e) {
let port = e.ports[0]
port.onmessage = function (e) {
if (e.data === 'get') {
port.postMessage(data)
} else {
data = e.data
}
}
}
-
webworker端(的代码就如上,只需注册一个onmessage监听信息的事件,客户端(即使用sharedWorker的标签页)发送message时就会触发。
-
注意webworker无法在本地使用,出于浏览器本身的安全机制,所以放在服务器上,worker.js和index.html在同一目录。
-
因为客户端和webworker端的通信不像websocket那样是双向的,所以客户端发送数据和接收数据要分成两步来处理。示例中会有两个按钮,分别对应的向sharedWorker发送数据的请求以及获取数据的请求,但他们本质上都是相同的事件–发送消息。
-
webworker端会进行判断,传递的数据为’get’时,就把变量data的值回传给客户端,其他情况,则把客户端传递过来的数据存储到data变量中。下面是客户端的代码:
// sharedWorker所要用到的js文件,不必打包到项目中,直接放到服务器即可
if (typeof Worker === "undefined") {
alert('当前浏览器不支持webworker')
} else {
let worker = new SharedWorker('worker.js')
worker.port.addEventListener('message', (e) => {
console.log('来自worker的数据:', e.data)
}, false)
worker.port.start()
window.worker = worker
}
// 获取和发送消息都是调用postMessage方法,我这里约定的是传递'get'表示获取数据。
window.worker.port.postMessage('get')
window.worker.port.postMessage('发送信息给worker')
- 页面A发送数据给worker,然后打开页面B,调用window.worker.port.postMessage(‘get’),即可收到页面A发送给worker的数据。