SocketIO се забавя при последователно 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,25 s.

Това е опростен 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>
    )
}

Той получава вече свързания сокет чрез подпори.

Компонентът се изобразява добре, докато има ~10 елемента, но след това се забавя и до 13-ия ред замръзва и дори не мога да затворя раздела, без да се налага първо да убия процеса.

Дебъгерът на Flask регистрира съобщението за всеки изобразен ред, но неизобразените редове (опитах с 25 като стойност за n) изглежда никога не са били изпращани.

Така че имам 2 въпроса:

  1. Защо flask не изпраща всяко съобщение? Някаква лоша опашка?
  2. Защо реакцията замръзва, когато задният сокет замръзва?

Освен това, ако направя msg клеймо за време, първите съобщения се изобразяват бързо, но разликата между клеймото за време и времево клеймо на React нараства много бързо с броя на съобщенията.


person Adcade    schedule 11.06.2021    source източник
comment
Не съм сигурен доколко това допринася за проблема, но вашето обратно извикване useEffect регистрира слушател за събитие и не го почиства, така че всеки път, когато компонентът се изобразява повторно, вие ще добавяте дублиращи се манипулатори, всичко за същото събитие.   -  person Miguel    schedule 12.06.2021
comment
Просто уча React, така че вероятно кодът има някои грешки. Благодаря, че го посочихте. Какво трябва да направя, за да поправя това? може би излишъкът от слушатели е това, което прави кода бавен   -  person Adcade    schedule 13.06.2021
comment
Не може да се обясни в коментар, но има много уроци за използването на Socket.IO с React. Пример: dev.to/ bravemaster619/.   -  person Miguel    schedule 13.06.2021


Отговори (1)


Реших го след коментара на @Miguel.

Накратко, функцията useEffect() се изпълнява при всяко изобразяване и всеки път, когато се изпълни, добавя нов манипулатор, без да изтрива предишния, така че след няколко изобразявания нещата експоненциално излизат извън контрол. Така че просто добавих ред за изтриване на манипулатора, когато приключи.

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

И сега се изобразява без проблеми.

person Adcade    schedule 14.06.2021