如何更新Python Flask应用,实现循环内逐次向JavaScript发送信息
实现逐次推送选秀结果的解决方案
要实现逐个发送选秀结果并允许用户交互,你需要用**服务器发送事件(SSE)**结合Flask的流式响应能力,同时配合前端处理用户输入后继续流程。以下是具体实现:
Flask 后端代码
from flask import Flask, request, jsonify, session, Response import json app = Flask(__name__) app.secret_key = "your-secret-key-here" # 必须设置才能使用session存储进度 # 模拟获取选秀顺位列表(实际可从前端请求或数据库读取) def get_draft_order(): return [(1, "Team A"), (2, "User Team"), (3, "Team B"), (4, "Team C")] # 模拟AI自动选秀逻辑 def simulate_ai_pick(team, pick_num): return { "pick_number": pick_num, "team": team, "player": f"AI选中球员-{team}-{pick_num}" } @app.route("/simulate-draft", methods=["POST"]) def simulate_draft(): user_team = request.json.get("user_team") draft_order = get_draft_order() # 初始化session存储选秀进度和结果 if "draft_progress" not in session: session["draft_progress"] = 0 session["user_team"] = user_team session["draft_results"] = [] def generate_stream(): while session["draft_progress"] < len(draft_order): pick_num, current_team = draft_order[session["draft_progress"]] if current_team == user_team: # 推送"等待用户选择"的信号给前端 yield f'data: {json.dumps({"type": "user_turn", "pick_number": pick_num, "team": current_team})}\n\n' break # 暂停循环,等待用户提交选择 # AI自动选秀,推送结果 ai_pick = simulate_ai_pick(current_team, pick_num) session["draft_results"].append(ai_pick) yield f'data: {json.dumps({"type": "ai_pick", "data": ai_pick})}\n\n' session["draft_progress"] += 1 # 所有顺位处理完成,推送结束信号 if session["draft_progress"] >= len(draft_order): yield f'data: {json.dumps({"type": "done", "results": session["draft_results"]})}\n\n' # 清空session数据 session.pop("draft_progress", None) session.pop("user_team", None) session.pop("draft_results", None) return Response(generate_stream(), mimetype="text/event-stream") # 接收用户提交的选秀选择 @app.route("/submit-user-pick", methods=["POST"]) def submit_user_pick(): user_pick_data = request.json user_team = session.get("user_team") # 将用户选择加入结果列表 session["draft_results"].append({ "pick_number": user_pick_data["pick_number"], "team": user_team, "player": user_pick_data["player"] }) session["draft_progress"] += 1 # 更新进度 return jsonify({"status": "success"})
JavaScript 前端代码
<!-- 假设页面上有这些元素 --> <div> <input type="text" id="user-team" placeholder="输入你的队伍名称"> <button onclick="startDraft()">开始选秀</button> </div> <div id="draft-results"></div> <!-- 用户选择弹窗 --> <div id="user-pick-modal" style="display: none;"> <h3>轮到你选择了!第<span id="current-pick-num"></span>顺位</h3> <input type="text" id="player-name" placeholder="输入选中球员名称"> <button onclick="submitUserPick()">确认选择</button> </div> <script> let currentEventSource; let currentPickNum; // 启动选秀模拟 function startDraft() { const userTeam = document.getElementById("user-team").value.trim(); if (!userTeam) return alert("请输入你的队伍名称"); // 创建SSE连接接收流式推送 currentEventSource = new EventSource("/simulate-draft", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ user_team: userTeam }) }); currentEventSource.onmessage = function(event) { const data = JSON.parse(event.data); switch (data.type) { case "ai_pick": displayPick(data.data); break; case "user_turn": currentEventSource.close(); showUserPickModal(data.pick_number); break; case "done": currentEventSource.close(); displayFinalResults(data.results); break; } }; currentEventSource.onerror = function(error) { console.error("选秀模拟出错:", error); currentEventSource.close(); }; } // 显示单条选秀结果 function displayPick(pickData) { const resultsDiv = document.getElementById("draft-results"); const pickElement = document.createElement("div"); pickElement.textContent = `第${pickData.pick_number}顺位:${pickData.team} 选择了 ${pickData.player}`; resultsDiv.appendChild(pickElement); } // 显示用户选择弹窗 function showUserPickModal(pickNum) { currentPickNum = pickNum; document.getElementById("current-pick-num").textContent = pickNum; document.getElementById("user-pick-modal").style.display = "block"; } // 提交用户选择并继续选秀 function submitUserPick() { const playerName = document.getElementById("player-name").value.trim(); if (!playerName) return alert("请输入球员名称"); fetch("/submit-user-pick", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ pick_number: currentPickNum, player: playerName }) }) .then(res => res.json()) .then(data => { if (data.status === "success") { document.getElementById("user-pick-modal").style.display = "none"; document.getElementById("player-name").value = ""; // 重新启动选秀流程,继续剩余顺位 startDraft(); } }); } // 显示最终选秀结果 function displayFinalResults(results) { const resultsDiv = document.getElementById("draft-results"); resultsDiv.innerHTML += "<h3>选秀完成!最终结果:</h3>"; results.forEach(pick => { const pickElement = document.createElement("div"); pickElement.textContent = `第${pick.pick_number}顺位:${pick.team} 选择了 ${pick.player}`; resultsDiv.appendChild(pickElement); }); } </script>
关键说明
- 流式响应与SSE:Flask通过
Response包裹生成器函数,设置text/event-stream类型实现服务器主动推送;前端用EventSource原生接收流式消息,无需手动处理分块。 - 进度存储:用Flask的
session存储当前选秀进度、用户队伍和已选结果,避免多用户流程冲突(生产环境可替换为数据库)。 - 用户交互暂停:遇到用户队伍时,后端推送
user_turn信号,前端关闭当前SSE连接,弹出输入框;用户提交选择后,后端更新进度,前端重新启动选秀流程继续剩余顺位。
内容的提问来源于stack exchange,提问作者user23907921
相关产品推荐
相关产品推荐

