首页 > 解决方案 > SocketIO 在连续发出时变慢()

问题描述

我正在尝试制作一个简单的脚本来将事件从 python 应用程序推送到客户端。我制作了一个ConsoleReact 组件,它使用 SocketIO 来接收事件,并且我正在使用 Flask SocketIO 推送消息。

这是我的app.py

from flask import Flask, request
from flask_socketio import SocketIO, send

app = Flask(__name__)
socketio = SocketIO(app, cors_allowed_origins='*')

@app.route('/send/<int:n>')
def send_n(n):
    for i in range(n):
        socketio.emit('console', str(i+1))
        socketio.sleep(0.1)
    return 'OK'


if __name__ == '__main__':
    socketio.run(app)

该函数send_n(n)只是将n事件推送到客户端,间隔 0.25 秒。

这是简化 Console的组件(它重现了不良行为):

import { useState, useEffect } from 'react'
import '../styles/console.css'
import { Socket } from 'socket.io-client'

interface ConsoleProps {
    socket: Socket
}

export default function Console(props: ConsoleProps) {
    const [messages, setMessages] = useState<string[]>([])

    useEffect(() => {
        props.socket.on('console', msg => {
            setMessages([...messages, `${new Date().toLocaleTimeString()} ${msg}`])
        })
    })

    return (
        <div className='console' style={{ height: '200px' }}>
            <ul>
                {messages.map((msg, i) => <li key={i}>{msg}</li>)}
            </ul>
        </div>
    )
}

它通过 props 接收已经连接的套接字。

该组件渲染得很好,直到它有大约 10 个元素,但随后它变慢了,到第 13 行它冻结了,我什至无法关闭选项卡而不必先终止进程。

Flask 的调试器为渲染的每一行注册消息,但未渲染的行(我尝试将 25 作为值n)似乎从未发送过。

所以我有两个问题:

  1. 为什么烧瓶不发送每条消息?某种糟糕的排队?
  2. 为什么后端套接字冻结时反应冻结?

此外,如果我制作msg时间戳,第一条消息会很快呈现,但后端时间戳和 React 时间戳之间的差异会随着消息数量的增加而迅速增长。

标签: pythonreactjsflasksocket.ioflask-socketio

解决方案


我按照@Miguel 的评论解决了它。

长话短说,该useEffect()函数在每次渲染时都会执行,并且每次执行时都会添加一个新的处理程序,而不会删除前一个处理程序,因此在几次渲染之后,事情就会以指数方式失控。所以我只是添加了一行来在处理程序完成时删除它。

useEffect(():any => {
    props.socket.on('console', msg => {
        setMessages([...messages, `${new Date().toLocaleTimeString()} ${msg}`])
    })
    return () => props.socket.off('console')
})

现在它的渲染没有问题。


推荐阅读