Можно ли предоставить пользователю отчеты о статусе из Flask во время циклической функции python? [Дубликат]

Что вам нужно знать:

    текст, который представляет несколько строк, также содержит непечатаемые символы между строками (мы называем их разделителями строк), как возврат каретки (CR - в строковых литералах, представленных как "\r") line line (LF - в строковых литералах, представленных как "\n")
  • , когда вы читаете данные с консоли, это позволяет пользователю вводить свой ответ, и когда он будет сделан, ему необходимо как-то подтверждают этот факт. Для этого пользователю необходимо нажать клавишу «enter» / «return» на клавиатуре. Важно то, что этот ключ, помимо обеспечения размещения пользовательских данных на стандартном входе (представленный System.in, который читается Scanner), также отправляет зависимые от ОС разделители строк (например, для Windows \r\n) после этого. Поэтому, когда вы запрашиваете у пользователя значение типа age, а пользовательские типы 42 и нажимаете enter, стандартный вход будет содержать "42\r\n".

Проблема

Scanner#nextInt (и другие методы Scanner#nextType) не позволяют сканеру потреблять эти разделители строк. Он прочитает их из System.in (как еще Сканер узнает, что больше нет цифр от пользователя, которые представляют age значение, чем перед пробелом?), Который удалит их со стандартного ввода, но он также будет кешем эти разделители строк внутри. Нам нужно помнить, что все методы Scanner всегда сканируются, начиная с кэшированного текста.

Теперь Scanner#nextLine() просто собирает и возвращает все символы , пока не найдет разделители строк (или конец потока). Но поскольку разделители строк после прочтения номера из консоли сразу обнаруживаются в кеше сканера, он возвращает пустую строку, что означает, что сканер не смог найти символ до этих разделителей строк (или конца потока). BTW nextLine также потребляет эти разделители строк.

Решение

Поэтому, когда вы хотите запросить номер, а затем для всей строки, избегая этой пустой строки в результате nextLine, либо

  • потребляет разделитель строк слева от nextInt из кеша сканеров, вызывая nextLine, или вызывая skip("\\R"), чтобы позволить Scanner пропускать часть, сопоставляемую с \R, которая представляет разделитель строк (подробнее о \R: https : //stackoverflow.com/a/31060125 )
  • вообще не используют nextInt (ни next, ни какие-либо методы nextTYPE). Вместо этого прочитайте целые строки данных по строке nextLine и номера разбора из каждой строки (при условии, что одна строка содержит только одно число) для правильного типа, например int, через Integer.parseInt.

BTW: Scanner#nextType методы могут пропускать разделители (по умолчанию все пробелы, такие как вкладки, разделители строк), в том числе кэшированные сканером, пока они не найдут следующее значение без разделителя (токен). Благодаря этому для ввода типа "42\r\n\r\n321\r\n\r\n\r\nfoobar" код

int num1 = sc.nextInt();
int num2 = sc.nextInt();
String name = sc.next();

сможет правильно назначить num1=42 num2=321 name=foobar.

10
задан davidism 11 August 2015 в 20:18
поделиться

1 ответ

Вы можете передавать данные в ответ, но вы не можете динамически обновлять шаблон так, как вы описываете. Шаблон создается один раз на стороне сервера, а затем отправляется клиенту. Вам нужно будет использовать JavaScript для чтения потокового ответа и вывода данных на стороне клиента.

Используйте XMLHttpRequest, чтобы сделать запрос к конечной точке, которая будет передавать данные. Затем периодически читайте поток, пока он не будет выполнен.

В этом примере используется очень простой формат сообщения: одна строка данных, за которой следует новая строка. Конечно, вы можете так же усложниться в разборе, сколько хотите, пока есть способ идентифицировать каждое сообщение. Например, вы можете вернуть объект JSON и декодировать его на клиенте.

from time import sleep
from flask import Flask, render_template
from math import sqrt

app = Flask(__name__)

@app.route('/')
def index():
    # render the template (below) that will use JavaScript to read the stream
    return render_template('index.html')

@app.route('/stream_sqrt')
def stream():
    def generate():
        for i in range(500):
            yield '{}\n'.format(sqrt(i))
            sleep(1)

    return app.response_class(generate(), mimetype='text/plain')

app.run()
<p>This is the latest output: <span id="latest"></span></p>
<p>This is all the output:</p>
<ul id="output"></ul>
<script>
    var latest = document.getElementById('latest');
    var output = document.getElementById('output');

    var xhr = new XMLHttpRequest();
    xhr.open('GET', '{{ url_for('stream') }}');
    xhr.send();
    var position = 0;

    function handleNewData() {
        // the response text include the entire response so far
        // split the messages, then take the messages that haven't been handled yet
        // position tracks how many messages have been handled
        // messages end with a newline, so split will always show one extra empty message at the end
        var messages = xhr.responseText.split('\n');
        messages.slice(position, -1).forEach(function(value) {
            latest.textContent = value;  // update the latest value in place
            // build and append a new item to a list to log all output
            var item = document.createElement('li');
            item.textContent = value;
            output.appendChild(item);
        });
        position = messages.length - 1;
    }

    var timer;
    timer = setInterval(function() {
        // check the response for new data
        handleNewData();
        // stop checking once the response has ended
        if (xhr.readyState == XMLHttpRequest.DONE) {
            clearInterval(timer);
            latest.textContent = 'Done';
        }
    }, 1000);
</script>
12
ответ дан davidism 31 August 2018 в 17:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: