|
|
@@ -17,11 +17,19 @@ export const useWebSocketStore = defineStore("websocket", () => {
|
|
|
/** 以底层 readyState 为准,避免 isConnected 与真实连接短暂不一致 */
|
|
|
const isSocketOpen = () => !!socket.value && socket.value.readyState === WebSocket.OPEN;
|
|
|
|
|
|
+ /** 上一笔尚未结束的 connect 的 resolve;刷新时 Header 与聊天页并发 connect 会顶替,必须结束旧 Promise */
|
|
|
+ let pendingConnectResolve: ((ok: boolean) => void) | null = null;
|
|
|
+
|
|
|
const connect = (url: string): Promise<boolean> => {
|
|
|
if (isSocketOpen() && lastConnectedUrl.value === url) {
|
|
|
isConnected.value = true;
|
|
|
return Promise.resolve(true);
|
|
|
}
|
|
|
+ if (pendingConnectResolve) {
|
|
|
+ const prev = pendingConnectResolve;
|
|
|
+ pendingConnectResolve = null;
|
|
|
+ prev(false);
|
|
|
+ }
|
|
|
if (socket.value) {
|
|
|
try {
|
|
|
socket.value.close();
|
|
|
@@ -36,17 +44,27 @@ export const useWebSocketStore = defineStore("websocket", () => {
|
|
|
lastConnectedUrl.value = url;
|
|
|
|
|
|
return new Promise(resolve => {
|
|
|
+ pendingConnectResolve = resolve;
|
|
|
+ const settle = (ok: boolean) => {
|
|
|
+ if (pendingConnectResolve === resolve) {
|
|
|
+ pendingConnectResolve = null;
|
|
|
+ resolve(ok);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
try {
|
|
|
const ws = new WebSocket(url);
|
|
|
socket.value = ws;
|
|
|
|
|
|
ws.onopen = () => {
|
|
|
+ if (socket.value !== ws) return;
|
|
|
isConnected.value = true;
|
|
|
isConnecting.value = false;
|
|
|
- resolve(true);
|
|
|
+ settle(true);
|
|
|
};
|
|
|
|
|
|
ws.onmessage = (event: MessageEvent) => {
|
|
|
+ if (socket.value !== ws) return;
|
|
|
try {
|
|
|
const message = JSON.parse(event.data);
|
|
|
const category = message.category || "message";
|
|
|
@@ -70,21 +88,26 @@ export const useWebSocketStore = defineStore("websocket", () => {
|
|
|
};
|
|
|
|
|
|
ws.onclose = () => {
|
|
|
+ // 必须校验实例:新 connect 关闭旧 socket 后,旧 onclose 仍会触发,否则会清空新连接导致「刷新后必现失败」
|
|
|
+ if (socket.value !== ws) return;
|
|
|
isConnected.value = false;
|
|
|
isConnecting.value = false;
|
|
|
socket.value = null;
|
|
|
+ // 握手未完成即关闭时结束 Promise(若已成功 onopen 已 settle,此处不再 resolve)
|
|
|
+ settle(false);
|
|
|
};
|
|
|
|
|
|
ws.onerror = () => {
|
|
|
+ if (socket.value !== ws) return;
|
|
|
isConnected.value = false;
|
|
|
isConnecting.value = false;
|
|
|
socket.value = null;
|
|
|
- resolve(false);
|
|
|
+ settle(false);
|
|
|
};
|
|
|
} catch (e) {
|
|
|
console.error("WebSocket 连接异常:", e);
|
|
|
isConnecting.value = false;
|
|
|
- resolve(false);
|
|
|
+ settle(false);
|
|
|
}
|
|
|
});
|
|
|
};
|