我正在尝试使用flask和JavaScript将生成的值实时流式传输到HTML。我希望在从flask中生成值后立即流式传输并显示这些值。但是,我目前无法将数据显示在HTML端。
这是Python Flask代码:
from flask import Flask, render_template
import time
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/stream_time')
def stream():
def generate():
t=time.time()
yield '{}\n'.format(time)
return app.response_class(generate(), mimetype='text/plain')
app.run
用于实时显示和更新值的HTML / JS代码:
<p>This is the current value: <span id="latest_value"></span></p>
<script>
var latest = document.getElementById('latest_value');
var xhr = new XMLHttpRequest();
xhr.open('GET', '{{ url_for('stream') }}');
xhr.send();
var message = xhr.responseText.split('\n');
latest.textContent = message;
</script>
当前,我没有在页面上显示任何值,我希望此值在字段上实时更新。我在做错什么以及如何解决此问题?
答案 0 :(得分:2)
JavaScript是异步工作的,在运行send()之后,它不等待响应,而是在获取带有文本的响应之前执行下一行。
要获得一个响应,您必须使用xhr.onload
(在send()
之前)来定义xhr
在获得响应时将运行的功能
xhr.onload = function () {
latest.textContent = xhr.responseText;
}
xhr.send()
最小工作代码
from flask import Flask, render_template_string
import time
app = Flask(__name__)
@app.route('/')
def index():
return render_template_string('''<p>This is the current value: <span id="latest_value"></span></p>
<script>
var latest = document.getElementById('latest_value');
var xhr = new XMLHttpRequest();
xhr.open('GET', '{{ url_for('stream') }}');
xhr.onload = function() {
latest.textContent = xhr.responseText;
}
xhr.send();
/* this lines will give `><` because `xhr.responseText` is still empty */
/* you can remove these lines */
console.log(">" + xhr.responseText + "<")
latest.textContent = ">" + xhr.responseText + "<";
</script>''')
@app.route('/stream_time')
def stream():
def generate():
current_time = time.strftime("%H:%M:%S\n")
print(current_time)
yield current_time
return app.response_class(generate(), mimetype='text/plain')
app.run()
要定期在浏览器中更新文本,您必须首先在生成器中使用while
循环来发送许多值。
为了测试,我还使用time.sleep(1)
发送较少的数据
def generate():
while True:
current_time = time.strftime("%H:%M:%S\n")
print(current_time)
yield current_time
time.sleep(1)
现在在JavaScript中,您必须使用xhr.onreadystatechange
来分配函数,该函数将在从服务器获取新数据时更新页面上的文本
xhr.onreadystatechange = function() {
var all_messages = xhr.responseText.split('\n');
last_message = all_messages.length - 2
latest.textContent = all_messages[last_message]
}
因为xhr.responseText
以\n
结尾,所以split('\n')
创建空消息作为列表all_messages
上的最后一个元素,因此我使用length - 2
而不是length - 1
最小工作代码
from flask import Flask, render_template_string
import time
app = Flask(__name__)
@app.route('/')
def index():
return render_template_string('''<p>This is the current value: <span id="latest_value"></span></p>
<script>
var latest = document.getElementById('latest_value');
var xhr = new XMLHttpRequest();
xhr.open('GET', '{{ url_for('stream') }}');
xhr.onreadystatechange = function() {
var all_lines = xhr.responseText.split('\\n');
last_line = all_lines.length - 2
latest.textContent = all_lines[last_line]
if (xhr.readyState == XMLHttpRequest.DONE) {
/*alert("The End of Stream");*/
latest.textContent = "The End of Stream"
}
}
xhr.send();
</script>''')
@app.route('/stream_time')
def stream():
def generate():
while True:
current_time = time.strftime("%H:%M:%S\n")
print(current_time)
yield current_time
time.sleep(1)
return app.response_class(generate(), mimetype='text/plain')
app.run()
顺便说一句:,因为我使用了render_template_string(html)
而不是render_template(filename)
,所以我不得不使用\\n
而不是\n