详细的错误堆栈信息:
WebSocket connection to 'ws://localhost:5173/ws/print/progress/1c211995-567d-448d-9e97-64b78253cb33?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGFpbXMiOnsidXNlck5hbWUiOiJtYW5hZ2VyIiwidXNlcklkIjoibWFuYWdlciJ9LCJpYXQiOjE3NjM1MTE1NTAsImV4cCI6MTc2MzU0NzU1MH0.KbBkouH-rHDQ1igOd372V1lzO8g81UgTWE9mjUJSoEw' failed: WebSocket is closed before the connection is established. close @ WebSocket.ts:263 stopProgress @ useWebSocketProgress.ts:62 (anonymous) @ useWebSocketProgress.ts:71 callWithErrorHandling @ chunk-CYLFN3VO.js?v=e5164ea1:2272 callWithAsyncErrorHandling @ chunk-CYLFN3VO.js?v=e5164ea1:2279 baseWatchOptions.call @ chunk-CYLFN3VO.js?v=e5164ea1:8342 job @ chunk-CYLFN3VO.js?v=e5164ea1:2002 callWithErrorHandling @ chunk-CYLFN3VO.js?v=e5164ea1:2272 flushJobs @ chunk-CYLFN3VO.js?v=e5164ea1:2480 Promise.then queueFlush @ chunk-CYLFN3VO.js?v=e5164ea1:2394 queueJob @ chunk-CYLFN3VO.js?v=e5164ea1:2389 baseWatchOptions.scheduler @ chunk-CYLFN3VO.js?v=e5164ea1:8354 effect2.scheduler @ chunk-CYLFN3VO.js?v=e5164ea1:2018 trigger @ chunk-CYLFN3VO.js?v=e5164ea1:516 endBatch @ chunk-CYLFN3VO.js?v=e5164ea1:574 notify @ chunk-CYLFN3VO.js?v=e5164ea1:836 trigger @ chunk-CYLFN3VO.js?v=e5164ea1:810 set value @ chunk-CYLFN3VO.js?v=e5164ea1:1682 watch.immediate @ PrintDrawer.vue:312 await in watch.immediate callWithErrorHandling @ chunk-CYLFN3VO.js?v=e5164ea1:2272 callWithAsyncErrorHandling @ chunk-CYLFN3VO.js?v=e5164ea1:2279 baseWatchOptions.call @ chunk-CYLFN3VO.js?v=e5164ea1:8342 job @ chunk-CYLFN3VO.js?v=e5164ea1:2002 flushPreFlushCbs @ chunk-CYLFN3VO.js?v=e5164ea1:2428 updateComponentPreRender @ chunk-CYLFN3VO.js?v=e5164ea1:7589 componentUpdateFn @ chunk-CYLFN3VO.js?v=e5164ea1:7508 run @ chunk-CYLFN3VO.js?v=e5164ea1:488 updateComponent @ chunk-CYLFN3VO.js?v=e5164ea1:7382 processComponent @ chunk-CYLFN3VO.js?v=e5164ea1:7317 patch @ chunk-CYLFN3VO.js?v=e5164ea1:6820 patchBlockChildren @ chunk-CYLFN3VO.js?v=e5164ea1:7176 processFragment @ chunk-CYLFN3VO.js?v=e5164ea1:7254 patch @ chunk-CYLFN3VO.js?v=e5164ea1:6794 componentUpdateFn @ chunk-CYLFN3VO.js?v=e5164ea1:7531 run @ chunk-CYLFN3VO.js?v=e5164ea1:488 runIfDirty @ chunk-CYLFN3VO.js?v=e5164ea1:526 callWithErrorHandling @ chunk-CYLFN3VO.js?v=e5164ea1:2272 flushJobs @ chunk-CYLFN3VO.js?v=e5164ea1:2480 Promise.then queueFlush @ chunk-CYLFN3VO.js?v=e5164ea1:2394 queueJob @ chunk-CYLFN3VO.js?v=e5164ea1:2389 effect2.scheduler @ chunk-CYLFN3VO.js?v=e5164ea1:7573 trigger @ chunk-CYLFN3VO.js?v=e5164ea1:516 endBatch @ chunk-CYLFN3VO.js?v=e5164ea1:574 notify @ chunk-CYLFN3VO.js?v=e5164ea1:836 trigger @ chunk-CYLFN3VO.js?v=e5164ea1:810 set value @ chunk-CYLFN3VO.js?v=e5164ea1:1682 handleClick @ BasePreventReClickButton.vue:51 callWithErrorHandling @ chunk-CYLFN3VO.js?v=e5164ea1:2272 callWithAsyncErrorHandling @ chunk-CYLFN3VO.js?v=e5164ea1:2279 emit @ chunk-CYLFN3VO.js?v=e5164ea1:8533 (anonymous) @ chunk-CYLFN3VO.js?v=e5164ea1:10242 handleClick @ element-plus.js?v=e5164ea1:7564 callWithErrorHandling @ chunk-CYLFN3VO.js?v=e5164ea1:2272 callWithAsyncErrorHandling @ chunk-CYLFN3VO.js?v=e5164ea1:2279 invoker @ chunk-CYLFN3VO.js?v=e5164ea1:11271 WebSocket.ts:140 WebSocket error: Event {isTrusted: true, type: 'error', target: WebSocket, currentTarget: WebSocket, eventPhase: 2, …} ws.onerror @ WebSocket.ts:140 error setupEventHandlers @ WebSocket.ts:139 connect @ WebSocket.ts:95 ManagedWebSocket @ WebSocket.ts:83 startProgress @ useWebSocketProgress.ts:42 watch.immediate @ PrintDrawer.vue:262 callWithErrorHandling @ chunk-CYLFN3VO.js?v=e5164ea1:2272 callWithAsyncErrorHandling @ chunk-CYLFN3VO.js?v=e5164ea1:2279 baseWatchOptions.call @ chunk-CYLFN3VO.js?v=e5164ea1:8342 job @ chunk-CYLFN3VO.js?v=e5164ea1:2002 flushPreFlushCbs @ chunk-CYLFN3VO.js?v=e5164ea1:2428 updateComponentPreRender @ chunk-CYLFN3VO.js?v=e5164ea1:7589 componentUpdateFn @ chunk-CYLFN3VO.js?v=e5164ea1:7508 run @ chunk-CYLFN3VO.js?v=e5164ea1:488 updateComponent @ chunk-CYLFN3VO.js?v=e5164ea1:7382 processComponent @ chunk-CYLFN3VO.js?v=e5164ea1:7317 patch @ chunk-CYLFN3VO.js?v=e5164ea1:6820 patchBlockChildren @ chunk-CYLFN3VO.js?v=e5164ea1:7176 processFragment @ chunk-CYLFN3VO.js?v=e5164ea1:7254 patch @ chunk-CYLFN3VO.js?v=e5164ea1:6794 componentUpdateFn @ chunk-CYLFN3VO.js?v=e5164ea1:7531 run @ chunk-CYLFN3VO.js?v=e5164ea1:488 runIfDirty @ chunk-CYLFN3VO.js?v=e5164ea1:526 callWithErrorHandling @ chunk-CYLFN3VO.js?v=e5164ea1:2272 flushJobs @ chunk-CYLFN3VO.js?v=e5164ea1:2480 Promise.then queueFlush @ chunk-CYLFN3VO.js?v=e5164ea1:2394 queueJob @ chunk-CYLFN3VO.js?v=e5164ea1:2389 effect2.scheduler @ chunk-CYLFN3VO.js?v=e5164ea1:7573 trigger @ chunk-CYLFN3VO.js?v=e5164ea1:516 endBatch @ chunk-CYLFN3VO.js?v=e5164ea1:574 notify @ chunk-CYLFN3VO.js?v=e5164ea1:836 trigger @ chunk-CYLFN3VO.js?v=e5164ea1:810 set value @ chunk-CYLFN3VO.js?v=e5164ea1:1682 handleClick @ BasePreventReClickButton.vue:51 callWithErrorHandling @ chunk-CYLFN3VO.js?v=e5164ea1:2272 callWithAsyncErrorHandling @ chunk-CYLFN3VO.js?v=e5164ea1:2279 emit @ chunk-CYLFN3VO.js?v=e5164ea1:8533 (anonymous) @ chunk-CYLFN3VO.js?v=e5164ea1:10242 handleClick @ element-plus.js?v=e5164ea1:7564 callWithErrorHandling @ chunk-CYLFN3VO.js?v=e5164ea1:2272 callWithAsyncErrorHandling @ chunk-CYLFN3VO.js?v=e5164ea1:2279 invoker @ chunk-CYLFN3VO.js?v=e5164ea1:11271 WebSocket.ts:147 WebSocket closed: 1006
请分析我的代码,解决这个问题: hook代码: import { useTokenStore } from "@/stores"; import { ManagedWebSocket } from "@/types"; import { onUnmounted, ref, watch } from "vue"; /** * WebSocket 进度 Hook */ export function useWebSocketProgress() { // 进度从1开始,增强使用体验,感觉一开始就工作了 const progressValue = ref(1); const { token } = useTokenStore(); let ws: ManagedWebSocket | null = null; /** * 开始进度 * 初始化WebSocket连接,并设置接收消息时的处理逻辑(计算进度) */ /** * 开始进度 * 初始化WebSocket连接,并设置接收消息时的处理逻辑(计算进度 * @param url 连接路径 * @param taskCount 任务数,默认为1(默认值本身就表示该参数是可选的) */ const startProgress = async (url: string, taskCount: number = 1) => { // 数据校验 if (!url) { throw new Error("无效的URL"); } if (!taskCount || taskCount <= 0) { throw new Error("无效的任务数"); } // 构建最终的 URL(包含 token 参数) let finalUrl = encodeURI(url); if (token) { const separator = finalUrl.includes("?") ? "&" : "?"; finalUrl += `${separator}token=${encodeURIComponent(token)}`; } // 实例化 ManagedWebSocket(被封装的WebSocket) ws = new ManagedWebSocket({ url: finalUrl, heartbeatInterval: 30000, // 心跳间隔30秒,在ManagedWebSocket类中已经封装心跳逻辑【启动心跳,每 30 秒发送一次心跳】,这里设置后就会生效,自动启动心跳 onMessage: (message) => { if (message.type === "UPDATE_PROGRESS" && taskCount) { // 计算进度 const progress = Math.trunc(((message.data as number) * 100) / taskCount); // 确保进度不倒退,确保进度大于1并且不超过99(确保进度条不满100%,保持显示,直到数据加载完毕页面渲染完成,进度才设置为100,从而触发隐藏) progressValue.value = Math.min(Math.max(progressValue.value, Math.max(progress, 1)), 99); } } }); }; /** * 停止进度 */ const stopProgress = () => { // 断开连接 if (ws) { ws.close(); ws = null; } }; // 监听进度值变化,当进度100时停止进度 watch( () => progressValue.value, () => { if (progressValue.value === 100) { stopProgress(); } } ); // 组件卸载时停止进度 onUnmounted(() => { stopProgress(); }); return { progressValue, startProgress, stopProgress }; } export default useWebSocketProgress; 组件调用hook: const { progressValue, startProgress, stopProgress } = useWebSocketProgress(); watch( () => props.printVisible, async (value) => { // 接收父组件传递过来的showDrawer值 drawerVisible.value = value; if (drawerVisible.value) { await startProgress(`/ws/print/progress/${requestId.value}`, props.printSelection.length); // 获取打印数据 // 打印标识为true,数据加载完成,开始渲染DOM printFlag.value = true; cleanupFrontendResources(); stopProgress(); // 确保DOM渲染完成 await nextTick(); // 所有工作全部完成,进度值设置为100,触发隐藏进度条 progressValue.value = 100; } }, { immediate: true } );
看了您的代码,我发现了几个关键问题。主要问题是在 WebSocket 连接建立之前就调用了 stopProgress(),导致连接被提前关闭。
问题分析
-
竞态条件:在
startProgress后立即调用stopProgress -
连接时机:WebSocket 连接是异步的,但代码没有等待连接建立
-
逻辑顺序错误:应该在所有工作完成后才停止进度,而不是中间停止
解决方案
1. 修改 Hook 代码
typescript
import { useTokenStore } from "@/stores";
import { ManagedWebSocket } from "@/types";
import { onUnmounted, ref, watch } from "vue";
/**
* WebSocket 进度 Hook
*/
export function useWebSocketProgress() {
const progressValue = ref(1);
const { token } = useTokenStore();
const isConnected = ref(false);
const isConnecting = ref(false);
let ws: ManagedWebSocket | null = null;
/**
* 开始进度
*/
const startProgress = async (url: string, taskCount: number = 1): Promise<void> => {
// 数据校验
if (!url) {
throw new Error("无效的URL");
}
if (!taskCount || taskCount <= 0) {
throw new Error("无效的任务数");
}
// 如果已经在连接中,先停止之前的连接
if (isConnecting.value || isConnected.value) {
stopProgress();
}
// 构建最终的 URL(包含 token 参数)
let finalUrl = encodeURI(url);
if (token) {
const separator = finalUrl.includes("?") ? "&" : "?";
finalUrl += `${separator}token=${encodeURIComponent(token)}`;
}
return new Promise((resolve, reject) => {
isConnecting.value = true;
try {
ws = new ManagedWebSocket({
url: finalUrl,
heartbeatInterval: 30000,
onMessage: (message) => {
if (message.type === "UPDATE_PROGRESS" && taskCount) {
const progress = Math.trunc(((message.data as number) * 100) / taskCount);
progressValue.value = Math.min(Math.max(progressValue.value, Math.max(progress, 1)), 99);
}
},
// 添加连接成功回调
onOpen: () => {
console.log('WebSocket连接已建立');
isConnecting.value = false;
isConnected.value = true;
resolve();
},
// 添加连接错误回调
onError: (error) => {
console.error('WebSocket连接错误:', error);
isConnecting.value = false;
isConnected.value = false;
reject(error);
},
// 添加连接关闭回调
onClose: () => {
console.log('WebSocket连接已关闭');
isConnecting.value = false;
isConnected.value = false;
}
});
// 设置连接超时
setTimeout(() => {
if (isConnecting.value && !isConnected.value) {
console.warn('WebSocket连接超时');
stopProgress();
reject(new Error('WebSocket连接超时'));
}
}, 5000);
} catch (error) {
isConnecting.value = false;
reject(error);
}
});
};
/**
* 停止进度
*/
const stopProgress = () => {
if (ws) {
ws.close();
ws = null;
}
isConnecting.value = false;
isConnected.value = false;
// 注意:这里不重置 progressValue,因为可能需要在UI中显示最终状态
};
// 监听进度值变化,当进度100时停止进度
watch(
() => progressValue.value,
(newValue) => {
if (newValue === 100) {
console.log('进度完成,停止WebSocket连接');
stopProgress();
}
}
);
// 组件卸载时停止进度
onUnmounted(() => {
stopProgress();
});
return {
progressValue,
isConnected,
isConnecting,
startProgress,
stopProgress
};
}
export default useWebSocketProgress;
2. 修改组件调用逻辑
typescript
const { progressValue, startProgress, stopProgress, isConnected } = useWebSocketProgress();
watch(
() => props.printVisible,
async (value) => {
drawerVisible.value = value;
if (drawerVisible.value) {
try {
// 1. 先启动进度监控,并等待连接建立
console.log('开始建立WebSocket连接...');
await startProgress(`/ws/print/progress/${requestId.value}`, props.printSelection.length);
console.log('WebSocket连接建立成功');
// 2. 获取打印数据(这里应该是您的数据获取逻辑)
// await fetchPrintData();
// 3. 打印标识为true,数据加载完成,开始渲染DOM
printFlag.value = true;
// 4. 清理前端资源
cleanupFrontendResources();
// 5. 确保DOM渲染完成
await nextTick();
// 6. 所有工作全部完成,进度值设置为100,触发隐藏进度条
// 这里设置100后,hook中的watch会自动调用stopProgress
progressValue.value = 100;
} catch (error) {
console.error('进度监控失败:', error);
// 如果连接失败,直接设置完成状态
progressValue.value = 100;
}
} else {
// 抽屉关闭时停止进度
stopProgress();
}
},
{ immediate: true }
);
3. 如果您能修改 ManagedWebSocket 类
在 ManagedWebSocket 类中添加连接状态回调:
typescript
// 在 ManagedWebSocket 类中添加这些回调
interface ManagedWebSocketOptions {
url: string;
heartbeatInterval?: number;
onMessage: (message: any) => void;
onOpen?: () => void;
onError?: (error: Event) => void;
onClose?: () => void;
}
class ManagedWebSocket {
private ws: WebSocket;
private heartbeatIntervalId?: number;
constructor(options: ManagedWebSocketOptions) {
this.ws = new WebSocket(options.url);
this.ws.onopen = () => {
console.log('WebSocket连接已打开');
// 启动心跳
if (options.heartbeatInterval) {
this.heartbeatIntervalId = setInterval(() => {
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify({ type: 'PING' }));
}
}, options.heartbeatInterval);
}
options.onOpen?.();
};
this.ws.onmessage = (event) => {
try {
const message = JSON.parse(event.data);
if (message.type !== 'PONG') { // 忽略心跳响应
options.onMessage(message);
}
} catch (error) {
console.error('解析WebSocket消息失败:', error);
}
};
this.ws.onerror = (error) => {
console.error('WebSocket错误:', error);
options.onError?.(error);
};
this.ws.onclose = () => {
console.log('WebSocket连接已关闭');
if (this.heartbeatIntervalId) {
clearInterval(this.heartbeatIntervalId);
}
options.onClose?.();
};
}
close() {
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.close(1000, '正常关闭');
}
}
}
关键修改点
-
添加连接状态管理:
isConnected和isConnecting状态 -
等待连接建立:使用 Promise 确保连接建立后再继续执行
-
移除中间的 stopProgress 调用:只在真正完成时设置 progressValue = 100
-
添加错误处理:捕获连接失败的情况
-
改进连接生命周期:确保正确的打开和关闭顺序
这样修改后,WebSocket 连接会在建立后才开始工作,避免了在连接建立前就被关闭的问题。
你是如何得知:主要问题是在 WebSocket 连接建立之前就调用了 stopProgress(),导致连接被提前关闭
我是通过分析代码执行时序和错误堆栈信息得出这个结论的。让我详细解释一下推理过程:
1. 从错误堆栈分析
从您提供的错误信息中可以看到:
text
WebSocket is closed before the connection is established. close @ WebSocket.ts:263 stopProgress @ useWebSocketProgress.ts:62 (anonymous) @ useWebSocketProgress.ts:71
关键路径:
-
WebSocket.ts:263- WebSocket 关闭 -
useWebSocketProgress.ts:62-stopProgress被调用 -
useWebSocketProgress.ts:71- 可能是 watch 监听器
这表明 stopProgress() 在 WebSocket 连接过程中就被调用了。
2. 从代码执行时序分析
看您的组件代码:
javascript
watch(
() => props.printVisible,
async (value) => {
if (drawerVisible.value) {
// 1. 开始 WebSocket 连接(异步)
await startProgress(`/ws/print/progress/${requestId.value}`, props.printSelection.length);
// 2. 获取打印数据
// 3. 设置打印标识
printFlag.value = true;
// 4. 清理资源
cleanupFrontendResources();
// 5. 立即停止进度!← 问题在这里
stopProgress();
// 6. 等待 DOM 渲染
await nextTick();
// 7. 设置进度为100
progressValue.value = 100;
}
}
);
问题在于:在 startProgress() 后立即调用了 stopProgress(),而 WebSocket 连接是异步建立的。
3. WebSocket 连接的生命周期
WebSocket 连接建立需要时间:
text
startProgress() 调用
↓
创建 WebSocket 实例(同步)
↓
开始建立 TCP 连接(异步,需要时间)
↓
握手过程(异步)
↓
连接建立完成(触发 onopen)
在 startProgress() 返回时,WebSocket 可能还处于 CONNECTING 状态,此时调用 stopProgress() 就会在连接建立前关闭它。
4. 从错误码判断
错误码 1006 表示:
The connection was closed abnormally, e.g., without a close frame being sent.
这通常发生在连接过程中被异常终止,而不是正常关闭。
5. 逻辑矛盾点
在您的代码中存在逻辑矛盾:
-
先调用
stopProgress()停止进度监控 -
然后又设置
progressValue.value = 100
如果进度监控已经停止了,设置进度值到 100 就没有意义了,因为 WebSocket 已经关闭,无法接收后续的进度更新。
6. 正确的执行时序应该是:
javascript
// 正确的时序 await startProgress() // 建立连接并开始监控 // ... 执行其他工作 progressValue.value = 100 // 工作完成,设置进度100 // → 触发 hook 中的 watch,自动调用 stopProgress()
而不是:
javascript
// 错误的时序 await startProgress() // 建立连接 stopProgress() // 立即关闭连接 ← 矛盾! // ... 执行其他工作 progressValue.value = 100 // 此时连接已关闭,这个设置没有意义
这种分析基于对异步操作、WebSocket 生命周期和代码执行时序的理解。通过仔细跟踪代码的执行路径和时序关系,就能发现这种"在连接建立前就关闭连接"的竞态条件问题。
其实这个hook是不是可以不用Promise?
您说得对,这个 hook 确实可以不用 Promise!让我们重新设计一个更简洁的版本。
简化版本(不使用 Promise)
1. 修改 Hook 代码
typescript
import { useTokenStore } from "@/stores";
import { ManagedWebSocket } from "@/types";
import { onUnmounted, ref, watch } from "vue";
/**
* WebSocket 进度 Hook(无 Promise 版本)
*/
export function useWebSocketProgress() {
const progressValue = ref(1);
const { token } = useTokenStore();
const isConnected = ref(false);
let ws: ManagedWebSocket | null = null;
/**
* 开始进度监控
*/
const startProgress = (url: string, taskCount: number = 1): void => {
// 数据校验
if (!url) {
console.error("无效的URL");
return;
}
if (!taskCount || taskCount <= 0) {
console.error("无效的任务数");
return;
}
// 先停止之前的连接(如果有)
stopProgress();
// 构建最终的 URL
let finalUrl = encodeURI(url);
if (token) {
const separator = finalUrl.includes("?") ? "&" : "?";
finalUrl += `${separator}token=${encodeURIComponent(token)}`;
}
// 重置进度
progressValue.value = 1;
try {
ws = new ManagedWebSocket({
url: finalUrl,
heartbeatInterval: 30000,
onMessage: (message) => {
if (message.type === "UPDATE_PROGRESS" && taskCount) {
const progress = Math.trunc(((message.data as number) * 100) / taskCount);
progressValue.value = Math.min(Math.max(progressValue.value, Math.max(progress, 1)), 99);
}
},
onOpen: () => {
console.log('WebSocket连接已建立');
isConnected.value = true;
},
onError: (error) => {
console.error('WebSocket连接错误:', error);
isConnected.value = false;
},
onClose: () => {
console.log('WebSocket连接已关闭');
isConnected.value = false;
}
});
} catch (error) {
console.error('创建WebSocket失败:', error);
isConnected.value = false;
}
};
/**
* 停止进度监控
*/
const stopProgress = (): void => {
if (ws) {
ws.close();
ws = null;
}
isConnected.value = false;
// 注意:这里不重置 progressValue,因为可能需要在UI中显示最终状态
};
/**
* 完成进度(设置进度为100并停止监控)
*/
const completeProgress = (): void => {
progressValue.value = 100;
stopProgress();
};
// 监听进度值变化,当进度100时自动停止
watch(
() => progressValue.value,
(newValue) => {
if (newValue === 100) {
console.log('进度完成,自动停止WebSocket连接');
stopProgress();
}
}
);
// 组件卸载时停止进度
onUnmounted(() => {
stopProgress();
});
return {
progressValue,
isConnected,
startProgress,
stopProgress,
completeProgress // 新增:完成进度的便捷方法
};
}
2. 修改组件调用逻辑
typescript
const { progressValue, startProgress, completeProgress, isConnected } = useWebSocketProgress();
watch(
() => props.printVisible,
async (value) => {
drawerVisible.value = value;
if (drawerVisible.value) {
console.log('开始进度监控...');
// 1. 启动进度监控(非阻塞,不需要await)
startProgress(`/ws/print/progress/${requestId.value}`, props.printSelection.length);
// 2. 获取打印数据
// await fetchPrintData();
// 3. 打印标识为true,数据加载完成,开始渲染DOM
printFlag.value = true;
// 4. 清理前端资源
cleanupFrontendResources();
// 5. 确保DOM渲染完成
await nextTick();
// 6. 所有工作全部完成,完成进度(设置100并停止监控)
completeProgress();
} else {
// 抽屉关闭时停止进度
stopProgress();
}
},
{ immediate: true }
);
3. 更简洁的组件调用方式
如果您想进一步简化,可以这样:
typescript
const { progressValue, startProgress, completeProgress } = useWebSocketProgress();
watch(
() => props.printVisible,
async (value) => {
drawerVisible.value = value;
if (drawerVisible.value) {
// 启动监控
startProgress(`/ws/print/progress/${requestId.value}`, props.printSelection.length);
// 执行所有工作...
// ... 您的业务逻辑
// 工作完成后完成进度
completeProgress();
}
},
{ immediate: true }
);
为什么可以不用 Promise?
-
WebSocket 连接是异步的:但我们可以通过回调来处理连接状态,不需要等待
-
进度监控是持续性的:不像一次性操作需要知道确切完成时间
-
错误处理更简单:连接失败时只需要在 UI 上反映状态,不需要中断主流程
-
代码更简洁:避免了复杂的异步控制流
优势
-
更简单:移除了复杂的 Promise 链
-
更健壮:避免了竞态条件
-
更直观:调用顺序更清晰
-
更好的错误恢复:连接失败不会阻塞主流程
这个版本应该能解决您的问题,同时保持代码的简洁性和可维护性。
1108

被折叠的 条评论
为什么被折叠?



