Flask SocketIO连续调用emit变慢及React前端卡顿问题咨询
问题1:前端页面冻结的原因
你当前的React代码存在两个致命问题:
- 首先
useEffect没有传入第二个依赖数组参数,这会导致每次组件渲染时都会重新绑定一次socket的console事件监听器。第一次收到消息触发重渲染,监听器数量变成2;第二次收到消息两个监听器同时触发,触发两次重渲染,监听器数量变成4,以此类推指数级增长,十几条消息后监听器数量就会涨到成千上万,直接占满浏览器主线程导致页面冻结。 - 其次你调用
setMessages时用的是闭包捕获的旧messages数组,不是最新的状态,会出现状态更新被覆盖的异常。
修复后的React组件代码如下:
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(() => { // 定义事件处理函数 const handleConsole = (msg: string) => { // 用函数式更新拿到最新的messages状态 setMessages(prev => [...prev, `${new Date().toLocaleTimeString()} ${msg}`]) } // 绑定事件 props.socket.on('console', handleConsole) // 返回清理函数,组件卸载/依赖变化时移除事件监听器 return () => { props.socket.off('console', handleConsole) } }, [props.socket]) // 仅当socket实例变化时重新执行effect return ( <div className='console' style={{ height: '200px' }}> <ul> {messages.map((msg, i) => <li key={i}>{msg}</li>)} </ul> </div> ) }
问题2:Flask看起来没发完所有消息的原因
这不是Flask的队列配置问题,是SocketIO的背压机制:当客户端主线程被占满无法处理收到的消息时,会停止向服务端发送消息确认包,服务端的SocketIO实例检测到客户端接收不过来,就会把后续要发送的消息暂存在队列里暂停发送,看起来就像消息没有发出去。你修复前端问题后这个现象会自动消失。
如果需要实现仅把消息推送给触发/send/<n>请求的用户,可优化Flask代码如下:
from flask import Flask, request from flask_socketio import SocketIO, send app = Flask(__name__) socketio = SocketIO(app, cors_allowed_origins='*') # 连接时记录用户对应的sid @socketio.on('connect') def handle_connect(): # 示例仅存在全局变量演示,生产环境可绑定到用户身份存储 global current_sid current_sid = request.sid @app.route('/send/<int:n>') def send_n(n): for i in range(n): # 指定发送给对应客户端,避免广播给所有连接用户 socketio.emit('console', str(i+1), to=current_sid) socketio.sleep(0.1) return 'OK' if __name__ == '__main__': socketio.run(app)
内容的提问来源于stack exchange,提问作者Adcade
相关产品推荐
相关产品推荐

