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
l oop в генераторе для отправки многих значений.
Для теста я также использую 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