如何用Flask与Python实现动态更新的变量展示?
Hey there! Let's break down what's going wrong with your code and how to fix it to get that auto-updating counter working properly.
The Root of the Problem
Your current code has a critical issue: Flask view functions are synchronous and blocking. When a request comes in, Flask waits for the view function to finish running and return a response before sending anything to the browser.
In your code, you've got a for loop with time.sleep(1) running 1000 times. That means the view function will take 1000 seconds (over 16 minutes!) to finish executing. During all that time:
- The browser sits there loading, waiting for a response that never arrives (until the loop finishes, which is way too long)
- Your terminal won't show a completed request log because the request is still being processed
- Even if you tried to put
return render_template(...)inside the loop, it would only return once (on the first iteration) and stop the function entirely—so you still wouldn't get an updating count.
Fixes: 2 Ways to Build an Auto-Updating Page
Let's look at two practical solutions, starting with a simple beginner-friendly option, then a more efficient one.
Option 1: Frontend Polling (Simple & Easy to Understand)
We'll split the logic into two parts:
- A background thread that handles the counting
- A frontend that periodically asks the backend for the latest count
Backend Code (app.py)
from flask import Flask, render_template, jsonify import time from threading import Thread app = Flask(__name__) current_count = 0 def run_counter(): global current_count # Count up to 999 (since range(0,1000) goes 0-999) while current_count < 999: time.sleep(1) current_count += 1 # Start the counter in a background thread (daemon=True means it stops when the app stops) Thread(target=run_counter, daemon=True).start() @app.route("/") def index(): # Just return the initial page—no waiting here! return render_template('index.html') @app.route("/get-count") def get_count(): # Return the latest count as JSON return jsonify({"count": current_count})
Frontend Code (templates/index.html)
<!DOCTYPE html> <html> <head> <title>Auto-Updating Counter</title> </head> <body> <h1>Current Count: <span id="counter-display">0</span></h1> <script> // Update the count every 1 second const updateInterval = setInterval(() => { fetch("/get-count") .then(response => response.json()) .then(data => { document.getElementById("counter-display").textContent = data.count; // Stop updating once we hit 999 if (data.count >= 999) { clearInterval(updateInterval); } }); }, 1000); </script> </body> </html>
Option 2: Server-Sent Events (SSE) – More Efficient
SSE lets the server push updates directly to the frontend without the frontend having to ask every second. It's perfect for one-way real-time updates like this.
Backend Code (app.py)
from flask import Flask, render_template, Response import time app = Flask(__name__) @app.route("/") def index(): return render_template('index.html') @app.route("/stream-count") def stream_count(): def generate_updates(): # Send a new count every second for 1000 iterations for count in range(0, 1000): time.sleep(1) # SSE requires this specific format: `data: [content]\n\n` yield f"data: {count}\n\n" # Return a streaming response with the correct MIME type for SSE return Response(generate_updates(), mimetype="text/event-stream")
Frontend Code (templates/index.html)
<!DOCTYPE html> <html> <head> <title>SSE Auto-Updating Counter</title> </head> <body> <h1>Current Count: <span id="counter-display">0</span></h1> <script> // Connect to the SSE stream const eventSource = new EventSource("/stream-count"); // Listen for new messages from the server eventSource.onmessage = function(event) { document.getElementById("counter-display").textContent = event.data; // Close the connection once we hit 999 if (parseInt(event.data) >= 999) { eventSource.close(); } }; // Handle any errors with the stream eventSource.onerror = function(error) { console.error("SSE connection error:", error); eventSource.close(); }; </script> </body> </html>
Quick Notes for Production
- Thread Safety: The global
current_countin Option 1 works for testing, but in production (with multiple server threads/processes), use a shared storage like Redis to avoid race conditions. - SSE Compatibility: SSE works in all modern browsers, but if you need support for older ones, stick with Option 1.
- Resource Limits: Don't run too many background threads—for larger apps, use a task queue like Celery instead.
内容的提问来源于stack exchange,提问作者Jcgo3003

