websocket實現(xiàn)的全雙工通信,真真太香了,以下是筆者在使用時,自己封裝的一個簡易js工具。若需要源碼,請移步這里
1 初始化連接
let socket = null; // 連接對象
let linkFailCount = 0; // 連接次數(shù),目前連接三次
let relinkLoading = null;// 重連全屏loading
/**
* @description: 初始化websocket
* @param {*} linkUrl url的地址
* @return {WebSocket} WebSocket對象
* @Author: liuxin
*/
function initWebSocket(linkUrl = "") {
// 正在連接或連接成功
if (socket && (socket.readyState < 2)) {
return socket;
}
// 如果地址由上層傳遞過來,則使用傳遞的地址
if (linkUrl) {
Window.apiConfig[process.env.NODE_ENV].wsUrl = linkUrl;
}
const url = Window.apiConfig[process.env.NODE_ENV].wsUrl;
socket = new WebSocket(url) // 創(chuàng)建對象
socket.onerror = webSocketOnError; // 連接錯誤處理
socket.onclose = closeWebsocket; // 連接關閉處理
socket.onopen = openWebsocket; // 連接打開處理
return socket;
}
2 連接打開回調
/**
* @description: 打開websocket回調函數(shù)處理
* @return {*}
* @Author: liuxin
*/
function openWebsocket() {
console.log("WebSocket連接打開...");
linkFailCount = 0;// 打開連接,連接次數(shù)改為0
// 加載動畫如果開啟,則關閉
if (relinkLoading) {
relinkLoading.close();
}
}
3 連接關閉回調
/**
* @description: 關閉websocket回調函數(shù)處理
* @return {*}
* @Author: liuxin
*/
function closeWebsocket() {
// 連接關閉時,立刻開啟重連機制
if (linkFailCount < 3 && socket && (socket.readyState >= 2)) {
// 開啟重連加載動畫
relinkLoading = ElLoading.service({
lock: true,
text: `連接關閉了,正在重連,請稍等...`,
})
initWebSocket();
}
}
4 連接錯誤處理
筆者這里會重連3次,重連的過程給與用戶提示,3次之后會提示用戶手動刷新
/**
* @description: 連接錯誤回調函數(shù)處理
* @param {*} e 錯誤對象
* @Author: liuxin
*/
function webSocketOnError(e) {
linkFailCount++;// 連接失敗的次數(shù)
if (relinkLoading) {
relinkLoading.close(); // 關閉重連加載動畫
}
//連接三次
if (linkFailCount < 3) {
initWebSocket();
// 開啟重連加載動畫
relinkLoading = ElLoading.service({
lock: true,
text: `第${linkFailCount}次連接失敗,正在嘗試第${linkFailCount + 1}次重新連接,請稍等...`,
})
} else {
ElMessageBox.confirm(
'連接失敗,是否嘗試刷新?',
'警告',
{
confirmButtonText: '刷新',
cancelButtonText: '取消',
type: 'warning',
"close-on-click-modal": false
}
)
.then((e) => {
if (e == "confirm") {
location.reload();
}
})
}
}
?5 數(shù)據(jù)處理
這里與后端約定的數(shù)據(jù)返回,加上type作為接口判斷依據(jù),因此這里不一定通用。
返回數(shù)據(jù)接口:{type:"xxx",data:{}}
/**
* @description: 處理websocket返回的數(shù)據(jù)
* @param {*} res 后端返回的數(shù)據(jù)
* @return {Object<JSON>}
* @Author: liuxin
*/
function webscoketDealData(res, type) {
const data = JSON.parse(res.data);
if (data.code !== 200) {
ElMessage.error("服務器錯誤" + data.message || "");
return { type: "error" };
}
const returnData = { type: data.type, data: data.data };
// 打印日志在前端
// if (type && type == data.type) {
// console.log('消息回來了-----', returnData);
// }
return returnData;
}
6 使用示例
const socket = initWebSocket(state.webSocketUrl); // 連接websocket
if (socket) {
// 這個寫法會導致多次進入監(jiān)聽事件
socket.addEventListener("message", (scev) => {
console.log(scev.data);
state.returnData.push(scev.data);
});
/* 監(jiān)聽socket關閉 */
socket.addEventListener("close", () => {
state.returnData.push("連接關閉");
});
}
sendMessage("escalator_data_detail", state.params); // 發(fā)送消息給后端請求數(shù)據(jù)
以下是在上述的基礎上,為整改頁面監(jiān)聽message多次進入的問題,進行的一個優(yōu)化處理文章來源:http://www.zghlxwxcb.cn/news/detail-503967.html
7 優(yōu)化消息處理
7.1 消息存儲在store倉庫
import store from "@/store";
/**
* @description: 初始化websocket
* @param {*} link url后更上的地址
* @return {WebSocket} WebSocket對象
* @Author: liuxin
*/
function initWebSocket() {
// 正在連接或連接成功
if (socket && (socket.readyState < 2)) {
return socket;
}
const url = Window.apiConfig[process.env.NODE_ENV].wsUrl;
socket = new WebSocket(url)//這里面的this都指向vue
socket.onerror = webSocketOnError;
socket.onclose = closeWebsocket;
socket.onopen = openWebsocket;
socket.onmessage = (res) => {
// console.log("消息回來了-----", res.data);
const data = JSON.parse(res.data);
if (data.code !== 200) {
ElMessage.error("服務器錯誤:" + data.message || "");
}
store.commit("commitSocketData", data); // 將消息存入倉庫中,而后使用則在倉庫取,不再監(jiān)聽message事件
};
return socket;
}
7.2 引入倉庫存儲
import { createStore } from 'vuex'
export default createStore({
state: {
// 用于存儲websocket返回的數(shù)據(jù) {后端的給定的type:后端的數(shù)據(jù)}
socketData: {
},
},
getters: {
/**
* @description: 獲取webscoket返回的數(shù)據(jù)
* @return {*}
* @Author: liuxin
*/
getSocketDataByType: (state) => (type) => {
if (Object.hasOwnProperty.call(state, type)) {
return state[type].data;
}
}
},
mutations: {
/**
* @description:
* @param {*} state state對象
* @param {*} commitData {type:"后端的api類型",data:"后端的數(shù)據(jù)"}
* @return {*}
* @Author: liuxin
*/
commitSocketData(state, commitData) {
// 如果沒有數(shù)據(jù),則直接返回
if (!commitData || !commitData.type) {
return;
}
state.socketData[commitData.type] = {}; // 初始化一個對象
state.socketData[commitData.type].data = commitData.data; // 添加數(shù)據(jù)存儲
state.socketData[commitData.type].timelyFlag = Date.now(); // 添加時間戳,保證每次后端的數(shù)據(jù)都能更新成功
},
},
})
7.3? 使用說明
直接引入store倉庫,監(jiān)聽倉庫數(shù)據(jù)變化文章來源地址http://www.zghlxwxcb.cn/news/detail-503967.html
import { useStore } from "vuex"; // 引入vuex
const store = useStore(); // 創(chuàng)建store對象
/**
* @description: 監(jiān)聽vuex獲取的數(shù)據(jù)變化,用于展示在前端
* @Author: liuxin
*/
watch(
() => store.state.socketData["escalator_data_detail"], // 這里escalator_data_detail是后端返回的type
(newData) => {
dealData(newData.data); // 處理數(shù)據(jù)
}
);
7.4編寫一個公共發(fā)送消息方法
/**
* @description: 發(fā)送websocket數(shù)據(jù)給后端
* @param {String} method 方法
* @param {JSON} params 參數(shù)
* @return {Object<JSON>}
* @Author: liuxin
*/
function sendMessage(method, params) {
const _data = {
api: method,
data: {
...params,
}
};
if (socket && socket.readyState == 1) {
// console.log("sendMessage----------", _data);
socket.send(JSON.stringify(_data))
} else {
// 監(jiān)聽socket打開
socket.addEventListener("open", () => {
// console.log("sendMessage -----open-----", _data);
socket.send(JSON.stringify(_data))
});
}
}
到了這里,關于vue3使用websocket簡易封裝,包含錯誤重連機制的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!