SharedWorker实现不同标签页共享一个websocket

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" });
    }
  },

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值