1.什么是SharedWorker?
SharedWorker是一种允许浏览器上下文(如多个标签页、iframe货窗口)共享同一个后台线程的Web API。使得这些上下文可以协同工作,共享数据和资源,无需每个页面单独创建线程。(如websocket,无需每个标签页都去创建连接。)
2.SharedWorker的使用
在public中创建一个SharedWorker.js文件
const ports = [] //存储所有标签页的端口引用
self.onconnect = (e) => {
const port = e.ports[0]
ports.push(port);
port.postMessage({ type: "" });
port.onmessage = (e) => {
console.log("接收到的数据",e)
}
}
在标签页中调用
const worker = new SharedWorker("/static/websocketShared.js");
worker.port.start();
worker.port.onmessage = (e) => {
console.log('接受到的数据',e)
}
worker.port.postMessage({type:''})
3.sharedWorker连接websocket
(1)在public中创建sharedWorker.js文件
let ws = null
const ports = [] //存储所有标签页的端口引用
let heartbeat = null
let isManualClose = false
function connect(publicParameter) {
ws = new WebSocket('yourself websocket link');
ws.onopen = () => {
connectOpen(publicParameter);
} // 打开时触发
ws.onmessage = message; // 拿到推送信息触发
ws.onerror = error; // 通信错误时触发
ws.onclose = close; // 连接取消时
}
const connectOpen = (publicParameter) => {
const state = ws.readyState;
if (state == 1) {
postMsg({ type: 'openSuccess', state })
authentication(publicParameter)
heartbeat = setInterval(() => {
wsHeartbeat()
}, 2000)
} else {
postMsg({ type: 'openFail', state })
}
}
const message = (e) => {
try {
let data = JSON.parse(e.data)
if (data.code == 2000 || data.code == 2201) {
postMsg(Object.assign({ type: 'message' }, data))
} else {
postMsg(Object.assign({ type: 'error' }, data))
if (data.msg_id == 101 && data.code == 46010) {
manualClone()
}
}
} catch (error) {
postMsg({ type: 'error', error: error })
}
}
const error = (error) => {
console.log("失败")
postMsg({ type: 'error', error: error })
}
const close = (row) => {
console.log("关闭")
clearInterval(heartbeat);
postMsg({ type: 'close' })
if (!isManualClose) {
connect()
}
}
//手动关闭
const manualClone = () => {
ws && ws.close && ws.close();
}
const postMsg = (params) => {
ports.forEach(port => {
port.postMessage(params);
})
}
/** 用户验证 */
function authentication(publicParameter) {
manualSend(publicParameter, 100)
}
/** 心跳验证 */
function wsHeartbeat() {
manualSend({}, 101)
}
/**
* 发送请求
* @param {data} 请求参数
* @param {msg_id} 消息类型
*/
const manualSend = (data, msg_id) => {
if (ws.readyState != 1) {
postMsg({ fail: true, state: ws.readyState })
return false;
}
let defaultData = {}
ws.send(JSON.stringify(defaultData));
return true;
}
self.onconnect = (e) => {
const port = e.ports[0]
ports.push(port);
if (!ws) {
//获取参数
port.postMessage({ type: "notConnected" });
};
port.onmessage = (e) => {
let data = e.data || {}
handleMessage(data, port)
}
}
/**
* 处理传递的数据
*/
const handleMessage = (data, port) => {
let type = data.type
switch (type) {
case "openWs":
let publicParameter = Object.assign({}, data)
connect(publicParameter)
break;
case "close":
if (ports.indexOf(port) > -1) {
ports.splice(ports.indexOf(port), 1)
}
break;
default:
break;
}
}
(2)封装js调用
import store from "@/store/index"
export const sharedWorkerWs = () => {
const worker = new SharedWorker("sharedWorker.js");
worker.port.start();
worker.port.onmessage = (e) => {
let data = e.data || {}
returnMsg(data, worker)
}
store.commit("setWorker", worker)
}
const getParams = () => {
const data = {
}
return data
}
const returnMsg = (data, worker) => {
let type = data.type
switch (type) {
case "notConnected":
worker.port.postMessage(getParams())
break;
case "openSuccess":
console.log("连接成功", data)
break;
case "openFail":
console.log("连接失败", data)
break;
case "message":
let msg_id = data.msg_id;
let dataMsg = data.data;
let params = {
msg_id,
data: dataMsg
}
break;
case "error":
console.log("错误", data)
break;
case "close":
console.log("关闭", data)
break;
default:
break;
}
}
(3)在组件中调用以及销毁
import { sharedWorkerWs } from "@/utils/sharedWorkerWs";
computed: {
worker() {
return this.$store.state.worker;
}
}
mounted() {
if (!this.worker) {
sharedWorkerWs();
}
window.addEventListener("beforeunload", this.handleBeforeUnload);
}
methods: {
handleBeforeUnload() {
if (this.worker && this.worker.port) {
this.worker.port.postMessage({ type: "close" });
}
},
},
beforeDestroy() {
window.removeEventListener("beforeunload", this.handleBeforeUnload);
// 组件销毁时也可以通知
if (this.worker && this.worker.port) {
this.worker.port.postMessage({ type: "close" });
}
},