обновление потоковых данных с flask в режиме реального времени - PullRequest
0 голосов
/ 24 апреля 2020

Я пытаюсь передать полученные значения в режиме реального времени в HTML, используя flask и JavaScript. Я хотел бы передавать и отображать значения без задержки, как только они будут получены из 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>

В настоящее время я не получаю никаких значений, отображаемых на странице, и мне бы хотелось, чтобы это поле обновлялось в режиме реального времени. Что я не так и как это исправить?

1 Ответ

2 голосов
/ 24 апреля 2020

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...