Display data streamed from a Flask view as it updates

前端 未结 1 408
暖寄归人
暖寄归人 2020-11-22 03:08

I have a view that generates data and streams it in real time. I can\'t figure out how to send this data to a variable that I can use in my HTML template. My current solut

相关标签:
1条回答
  • 2020-11-22 04:03

    You can stream data in a response, but you can't dynamically update a template the way you describe. The template is rendered once on the server side, then sent to the client. You'll need to use JavaScript to read the streamed response and output the data on the client side.

    Use XMLHttpRequest to make a request to the endpoint that will stream the data. Then periodically read from the stream until it is done.

    This example assumes a very simple message format: a single line of data, followed by a newline. You can of course get as complicated in parsing as you like, as long as there's a way to identify each message. For example, you could return a JSON object and decode it on the client.

    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>
    
    0 讨论(0)
提交回复
热议问题