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

HTTP与WS调用后如何返回实际数据而非Promise?问题排查

问题分析与解决方案

首先得明确一个核心点:JavaScript里的异步操作(比如HTTP请求、WebSocket消息)的结果,没办法同步拿到——你必须等待异步操作完成,才能获取到实际数据。你看到的Promise<Pending>就是因为代码还没等异步流程走完就去拿结果了,而且你的代码里还有两个关键错误:

你的代码里的问题

  1. WebSocket消息收集时机错误:你在onopen回调里直接返回messages数组,但这时候WebSocket还没开始接收消息呢!onmessage是异步触发的,当你return messages的时候,它还是空数组,只有后续收到消息才会往里面push数据,但这时候你的wsRequest这个Promise已经resolve成空数组了。
  2. 错误地认为then能直接返回同步值:wsRequest.then(res => res)返回的依然是Promise,因为then本身就是异步方法,你同步打印data的时候,异步流程还没完成,所以看到的是pending状态的Promise。

修复方案

我们需要把WebSocket的消息收集过程包装成一个Promise,这样就能在消息接收完成后再resolve出最终的数组。这里假设你要收集100条数据(对应你的SQL LIMIT 100),或者等服务器发送完数据后关闭WebSocket,两种情况的处理方式如下:

方案1:用Promise包装WebSocket流程,收集指定数量的消息

const authenticationRequest = () => 
  axios.post(authenticationUrl, { user: username, password })
    .then((response) => response.data)
    .catch((error) => console.error('Error Response', error));

// 把WebSocket请求包装成返回Promise的函数
const getWsMessages = async (token) => {
  return new Promise((resolve, reject) => {
    const webSocketRequest = new WebSocket(topicDataUrl);
    const messages = [];
    const expectedCount = 100; // 对应SQL语句的LIMIT 100

    webSocketRequest.onopen = () => {
      const firstMessage = { 
        token: token, 
        stats: 2, 
        sql: "SELECT * FROM cc_payments LIMIT 100", 
        live: false 
      };
      webSocketRequest.send(JSON.stringify(firstMessage));
    };

    webSocketRequest.onmessage = (streamEvent) => {
      const message = JSON.parse(streamEvent.data);
      if (message.type === 'RECORD') {
        messages.push(message.data.value);
        // 收集到指定数量的消息后,resolve并关闭WebSocket
        if (messages.length === expectedCount) {
          webSocketRequest.close();
          resolve(messages);
        }
      }
    };

    // 处理WebSocket错误
    webSocketRequest.onerror = (error) => {
      reject(error);
      webSocketRequest.close();
    };

    // 万一服务器提前关闭连接,返回已收集的消息
    webSocketRequest.onclose = () => {
      if (messages.length > 0) {
        resolve(messages);
      } else {
        reject(new Error('WebSocket closed without receiving messages'));
      }
    };
  });
};

// 用async/await简化异步流程
const fetchData = async () => {
  try {
    const reqToken = await authenticationRequest();
    const data = await getWsMessages(reqToken);
    console.log(data, 'DATA'); // 这里就能拿到实际的100条数据数组了
    return data;
  } catch (error) {
    console.error('Fetch failed:', error);
  }
};

// 启动整个异步流程
fetchData();

方案2:监听WebSocket关闭事件(若服务器发送完数据主动关闭连接)

如果服务器在发送完所有数据后会主动关闭WebSocket,你可以去掉onmessage里的数量判断,直接在onclose事件中resolve已收集的消息:

// 修改getWsMessages里的onmessage和onclose部分
webSocketRequest.onmessage = (streamEvent) => {
  const message = JSON.parse(streamEvent.data);
  if (message.type === 'RECORD') {
    messages.push(message.data.value);
  }
};

webSocketRequest.onclose = () => {
  if (messages.length === 0) {
    reject(new Error('No messages received before connection closed'));
  } else {
    resolve(messages);
  }
};

关键知识点回顾

  • 所有异步操作(axios、WebSocket)的结果都只能通过**Promise的then/catch或者async/await**来获取,没法同步拿到。
  • 当你需要等待多个异步步骤(先拿token,再连WebSocket收消息),必须把这些步骤串联成异步流程,不能在异步操作还没完成的时候就返回结果。
  • WebSocket的onmessage是事件驱动的,必须用Promise来封装这个事件流,才能把异步的消息收集转换成可以等待的Promise。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 09:37:40