Vue3+TypeScript WebSocket连接报错1006:WebSocket is closed before the connection is established.

详细的错误堆栈信息:

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(),导致连接被提前关闭。

问题分析

  1. 竞态条件:在 startProgress 后立即调用 stopProgress

  2. 连接时机:WebSocket 连接是异步的,但代码没有等待连接建立

  3. 逻辑顺序错误:应该在所有工作完成后才停止进度,而不是中间停止

解决方案

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, '正常关闭');
    }
  }
}

关键修改点

  1. 添加连接状态管理isConnected 和 isConnecting 状态

  2. 等待连接建立:使用 Promise 确保连接建立后再继续执行

  3. 移除中间的 stopProgress 调用:只在真正完成时设置 progressValue = 100

  4. 添加错误处理:捕获连接失败的情况

  5. 改进连接生命周期:确保正确的打开和关闭顺序

这样修改后,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?

  1. WebSocket 连接是异步的:但我们可以通过回调来处理连接状态,不需要等待

  2. 进度监控是持续性的:不像一次性操作需要知道确切完成时间

  3. 错误处理更简单:连接失败时只需要在 UI 上反映状态,不需要中断主流程

  4. 代码更简洁:避免了复杂的异步控制流

优势

  • 更简单:移除了复杂的 Promise 链

  • 更健壮:避免了竞态条件

  • 更直观:调用顺序更清晰

  • 更好的错误恢复:连接失败不会阻塞主流程

这个版本应该能解决您的问题,同时保持代码的简洁性和可维护性。


修改前的代码:

修改后的代码:

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值