【问题标题】:WebSocket readyState stuck at 0 after a couple of messages are sent发送几条消息后,WebSocket readyState 停留在 0
【发布时间】:2021-05-18 00:17:03
【问题描述】:

我正在尝试使用 Web 套接字开发一个实时聊天应用程序并做出反应,但是在我尝试提交几条消息(大约 30 条)后,Web 套接字卡在了 CONNECTING 状态。我已经设置好了,所以当它发送消息时,它禁用了发送按钮,以防止用户发送垃圾邮件太快,但不幸的是我仍然遇到同样的问题。

// id is a uuid() string
const ws = new WebSocket(`ws://localhost:3001/chat/${id}`);

useEffect(() => {
        ws.onmessage = function(evt){
            try{
                const user_id = parseInt(evt.data.split("")[0]);
                const message = evt.data.slice(1);
                const currentTime = new Date();
                const currentUTC = currentTime.toUTCString();
                const timestamp = new Date(currentUTC);
                setMessages(messages => [...messages, {user_id, message, timestamp}])
            } catch(e){
                console.log(e);
            }
        }

        ws.onclose = function(evt){
            console.log("DISCONNECTED!!")
            ws.close();
        }

        ws.onerror = function(evt){
            console.log(evt);
            ws.close();
        }
    }, []);


useEffect(() => {
        async function postMessageToAPI() {
            
            const messsageToSend = {
                unique_id: id,
                message: formData.message, 
                user_id: user.id, 
                group_chat_id: room.id
            }
            // Convert to unviersal time UTC and send it to database
            let currentUTC = new Date();
            currentUTC.toUTCString();
            messsageToSend.timestamp = currentUTC;

            await AnonChatApi.sendChatMessage(messsageToSend);
        }

        if(sendMessage){
            ws.onopen = function(){
                // add user_id to the start of the message string
                const message = `${user.id}` + formData.message;
                ws.send(message);
            }
            postMessageToAPI();
            resetFormData();
            setTimeout(() => {
                setSendMessage(false)
            }, 1000);
        }
    }, [sendMessage]);

const goBackHome = () => {
        ws.close();
        history.push('/');
    }

【问题讨论】:

  • 你没有显示打开或关闭套接字的代码,你能补充一下吗?
  • 如果您在每条消息后都关闭套接字,那么您可能不应该使用 websocket。我无法从您的代码中判断是否是这种情况,但您的描述似乎暗示了这一点。
  • @Codebling,我添加了打开和关闭 websocket 的代码。我不是在每条消息后都尝试关闭 websocket,我只是通过一次发送多条消息来测试错误,它最终卡在 readyState 0 上。感谢您查看我的代码!

标签: javascript reactjs websocket


【解决方案1】:

我可以看到您正在使用 Hooks,因此您还必须使用功能组件。 我认为初始化 websocket 的代码是否正确

const ws = new WebSocket(`ws://localhost:3001/chat/${id}`);

在函数的顶部?

提醒一下,每当你的组件被渲染时,定义你的函数组件的函数就会运行。任何未保存在状态中的东西都会丢失。这包括你的 websocket - 每次渲染都会创建一个新的 websocket,你的异步函数可能会在旧的 websocket 上发送数据(来自以前的渲染),React 可能会在控制台中警告你有内存泄漏。

useEffect 是这里的正确做法,但是 websocket 也需要保存在 state 中。

YourFunctionComponent() {
  const [ws, setWs] = useState(null);

  useEffect(() => {
    if (ws == null) {
      setWs(new WebSocket(`ws://localhost:3001/chat/${id}`));
    }
    return () => {
      // A function returned from useEffect will
      // get called on component unmount. 
      // Use this function to clean up your connection and 
      // close your websocket!

      // clean up, e.g.
      // ws.send('closing due to unmount!');
      
      ws.close();
      setWs(null);
    }
  }, [ws, setWs]);


  // Add `ws` as a dependency in the useEffect()s you posted above
  useEffect(() => {
    ws.onmessage = function(evt){
[--snip--]
    }
  }, [ws]);

  useEffect(() => {
    async function postMessageToAPI() {
[--snip--]
    }
  }, [sendMessage, ws]);
}

【讨论】:

  • 解决了这个问题,谢谢!我还需要添加检查以等待设置 ws 否则我会收到诸如“无法读取 null 的消息”之类的错误。
  • @Allen 真棒!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多