You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用WebSocket加try/catch仍出现Uncaught (in promise)错误求助

问题描述

我通过WebSocket API获取数据,收到消息后会检查是否存在错误,若有错误则拒绝Promise请求。但拒绝请求后,控制台仍出现Uncaught (in promise)错误,即便已用try/catch包裹所有代码。相关代码如下:

Service类

class Service {
  static getUser() {
    return new Promise((resolve, reject) => {
      // 试过用try/catch包裹整个函数体,但问题依旧
      const messageReceiveCallback = (message) => {
        try {
          const data = JSON.parse(message.data);
          if (data.hasError) {
           // 错误发生在这里
            reject(data);
          } else {
            resolve(data);
          }
        } catch (error) {
           // 错误没有走到这里
          reject(error);
        } finally {
          derivService.socketConnection.removeEventListener(
            "message",
            messageReceiveCallback
          );
        }
      };

      socketConnection.addEventListener(
        "message",
        messageReceiveCallback
      );
      publicApi.getUser(apiPayload);

    })
  }
}

React组件

const retrieveUser = async () => {
    try {
      await Service.getUser(payload); // 不加await会看到两次错误,加了只看到一次
    } catch (e: any) {
      console.log("eee", e);
    }
  };

  useEffect(() => {
    retrieveUser();
  }, []);
问题根源

问题出在Promise状态只能被修改一次:当WebSocket的message事件被多次触发时(比如服务器返回多条消息、事件重复触发),第一次调用reject后,Promise已经进入rejected终态,后续再调用reject或resolve会直接抛出未捕获错误——这个错误无法被外层try/catch捕获,因为它是在Promise状态确定后执行的无效状态修改操作。

另外,虽然你在finally里移除了事件监听,但如果第一次回调执行完成前,已有多个message事件被放入事件队列,回调还是会被多次执行,导致重复修改Promise状态。

修复方案

在Promise的executor函数里加一个状态标志,确保resolve/reject只会被调用一次:

class Service {
  static getUser() {
    return new Promise((resolve, reject) => {
      let isHandled = false; // 标记是否已处理过Promise状态
      const messageReceiveCallback = (message) => {
        if (isHandled) return; // 已处理过直接返回,避免重复操作
        
        try {
          const data = JSON.parse(message.data);
          isHandled = true; // 先标记为已处理,再修改状态
          if (data.hasError) {
            reject(data);
          } else {
            resolve(data);
          }
        } catch (error) {
          isHandled = true;
          reject(error);
        } finally {
          derivService.socketConnection.removeEventListener(
            "message",
            messageReceiveCallback
          );
        }
      };

      socketConnection.addEventListener("message", messageReceiveCallback);
      publicApi.getUser(apiPayload);
    })
  }
}
额外优化

可以给WebSocket请求加超时处理,避免因网络问题导致Promise一直处于pending:

static getUser() {
  return new Promise((resolve, reject) => {
    let isHandled = false;
    // 设置10秒超时
    const timeoutTimer = setTimeout(() => {
      if (!isHandled) {
        isHandled = true;
        reject(new Error("请求超时,请检查网络"));
        socketConnection.removeEventListener("message", messageReceiveCallback);
      }
    }, 10000);

    const messageReceiveCallback = (message) => {
      if (isHandled) return;
      clearTimeout(timeoutTimer); // 收到消息后清除超时定时器
      
      try {
        const data = JSON.parse(message.data);
        isHandled = true;
        if (data.hasError) {
          reject(data);
        } else {
          resolve(data);
        }
      } catch (error) {
        isHandled = true;
        reject(error);
      } finally {
        socketConnection.removeEventListener("message", messageReceiveCallback);
      }
    };

    socketConnection.addEventListener("message", messageReceiveCallback);
    publicApi.getUser(apiPayload);
  })
}

内容的提问来源于stack exchange,提问作者Amit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 17:23:17