SocketIO 连续 emit() 变慢

SocketIO slowing on consecutive emit()

我正在尝试制作一个简单的脚本来将事件从 python 应用程序推送到客户端。我制作了一个 Console React 组件,它使用 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.25s。

这是 简化的 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. 为什么 flask 没有发送每条消息?某种糟糕的排队?
  2. 为什么当后端套接字冻结时反应会冻结?

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

我根据@Miguel 的评论解决了它。

长话短说,useEffect() 函数在每次渲染时执行,每次执行时都会添加一个新的处理程序 而不会删除之前的处理程序 ,所以在少数会使事情呈指数级失控。所以我只是添加了一行以在它完成时删除处理程序。

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

现在渲染没有问题了。