Flask中Python脚本执行时如何传值给JS函数更新进度条
实时进度更新实现方案
普通的Flask视图函数会等所有逻辑执行完毕才一次性返回响应给前端,没法中途推送进度数据,用SSE(服务器发送事件) 就能实现你要的效果,比WebSocket轻量很多,不需要额外安装依赖,新手很容易跑通。
后端(views.py)改造
把原来的单一视图拆成两个:一个负责返回渲染好的主页,一个专门执行长任务、向前端流式推送进度值。
from flask import Flask, render_template, Response import time # 仅用于模拟耗时任务,实际使用可删除 app = Flask(__name__) # 主页路由,仅负责返回页面 @app.route('/') def home(): return render_template("home.html") # 长任务+进度推送接口,SSE专用 @app.route('/run-tasks') def run_tasks(): def generate_progress(): # 把所有待执行任务按顺序放进列表,方便统计总进度 tasks = [ # 任务1:计算list1总和 lambda: ( sum([1, 2, 3, 4, 5]) ), # 任务2:计算list2总和 lambda: ( sum([10, 20, 30, 40, 50]) ), # 剩余任务按顺序往后追加即可,以下为模拟耗时任务示例 lambda: time.sleep(1), lambda: time.sleep(1), lambda: time.sleep(1), ] total_task_num = len(tasks) # 逐个执行任务,每完成一个就推送一次进度 for index, task in enumerate(tasks): task() # 执行当前任务 current_progress = int((index + 1) / total_task_num * 100) # SSE固定消息格式:必须以data:开头,结尾加两个换行符 yield f"data:{current_progress}\n\n" # 所有任务完成推送100%进度 yield "data:100\n\n" # 返回流式响应,必须指定Content-Type为text/event-stream return Response(generate_progress(), mimetype='text/event-stream') if __name__ == '__main__': app.run(debug=True)
你原来写的for循环累加逻辑完全可以保留,直接替换对应lambda里的sum代码就行,不影响进度推送。
前端(home.html)改造
保留你已经写好的updateProgressBar函数,新增SSE连接逻辑,收到后端推送的进度值就更新进度条即可。以下是完整可运行的示例,包含进度条基础样式:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>任务执行进度</title> <style> /* 进度条样式可根据需求自行修改 */ .progress { width: 600px; height: 32px; border-radius: 16px; background: #f0f0f0; margin: 100px auto; position: relative; overflow: hidden; } .progress__fill { height: 100%; width: 0%; background: #2563eb; transition: width 0.2s ease; } .progress__text { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); margin: 0; font-size: 14px; color: #1f2937; } </style> </head> <body> <!-- 进度条DOM结构 --> <div class="progress"> <div class="progress__fill"></div> <p class="progress__text">0%</p> </div> <script> // 你原有写好的进度条更新函数,无需修改 function updateProgressBar(progressBar, value) { value = Math.round(value); progressBar.querySelector(".progress__fill").style.width = `${value}%`; progressBar.querySelector(".progress__text").textContent = `${value}%`; } // 页面加载完成后建立SSE连接 document.addEventListener('DOMContentLoaded', () => { const progressBarEl = document.querySelector('.progress'); // 连接后端的进度推送接口 const sseClient = new EventSource('/run-tasks'); // 收到后端推送的进度数据时触发更新 sseClient.onmessage = (event) => { const progressVal = parseInt(event.data); updateProgressBar(progressBarEl, progressVal); // 进度到100%时关闭连接 if (progressVal >= 100) { sseClient.close(); // 可在这里追加任务完成后的逻辑,比如弹出提示、跳转页面等 } } // 连接出错时自动关闭 sseClient.onerror = () => { sseClient.close(); } }) </script> </body> </html>
常见问题说明
- 本地开发测试时如果遇到进度等所有任务跑完才一次性跳到100%,先检查是否开启了Flask的多线程/多进程,默认开发服务器一般不会有该问题;如果后续用Nginx部署,记得关闭对应路径的
proxy_buffering配置 - 如果任务需要用到用户提交的表单/URL参数,和普通Flask路由一样用
request对象获取即可,写法没有区别 - SSE是单向通信通道,仅支持服务端向前端推送数据,完全匹配进度更新的场景,不需要引入额外的第三方服务,学习成本远低于WebSocket
内容的提问来源于stack exchange,提问作者Nicholas
相关产品推荐
相关产品推荐

