Javascript 更新时显示烧瓶视图中的数据流

Javascript 更新时显示烧瓶视图中的数据流,javascript,python,flask,stream,Javascript,Python,Flask,Stream,我有一个视图,可以实时生成数据并将其流式传输。我不知道如何将此数据发送到可以在HTML模板中使用的变量。我当前的解决方案只是在数据到达时将其输出到一个空白页面,这是可行的,但我希望将其包含在一个带有格式的较大页面中。如何在数据流传输到页面时更新、格式化和显示数据 import flask import time, math app = flask.Flask(__name__) @app.route('/') def index(): def inner(): # s

我有一个视图,可以实时生成数据并将其流式传输。我不知道如何将此数据发送到可以在HTML模板中使用的变量。我当前的解决方案只是在数据到达时将其输出到一个空白页面,这是可行的,但我希望将其包含在一个带有格式的较大页面中。如何在数据流传输到页面时更新、格式化和显示数据

import flask
import time, math

app = flask.Flask(__name__)

@app.route('/')
def index():
    def inner():
        # simulate a long process to watch
        for i in range(500):
            j = math.sqrt(i)
            time.sleep(1)
            # this value should be inserted into an HTML template
            yield str(i) + '<br/>\n'
    return flask.Response(inner(), mimetype='text/html')

app.run(debug=True)
导入烧瓶
输入时间、数学
app=烧瓶。烧瓶(\uuuuu名称\uuuuuuu)
@应用程序路径(“/”)
def index():
def inner():
#模拟要观看的长过程
对于范围(500)内的i:
j=数学sqrt(i)
时间。睡眠(1)
#此值应插入到HTML模板中
收益率str(i)+'
\n' return flask.Response(inner(),mimetype='text/html') app.run(debug=True)
您可以在响应中流式传输数据,但不能按照您描述的方式动态更新模板。模板在服务器端呈现一次,然后发送到客户端

一种解决方案是使用JavaScript读取流式响应并在客户端输出数据。使用
XMLHttpRequest
向将流式传输数据的端点发出请求。然后定期从流中读取数据,直到完成为止

这引入了复杂性,但允许直接更新页面,并提供对输出外观的完全控制。下面的示例通过显示当前值和所有值的日志来演示这一点

本例假设一种非常简单的消息格式:一行数据,后跟一个换行符。这可以根据需要变得复杂,只要有一种方法来识别每条消息。例如,每个循环都可以返回一个JSON对象,由客户机解码

从数学导入sqrt
从时间上导入睡眠
从烧瓶导入烧瓶,渲染\u模板
app=烧瓶(名称)
@附件路线(“/”)
def index():
返回渲染模板(“index.html”)
@应用程序路径(“/stream”)
def stream():
def generate():
对于范围(500)内的i:
产生“{}\n”。格式(sqrt(i))
睡眠(1)
返回app.response_类(generate(),mimetype=“text/plain”)
这是最新的输出:

这是所有的输出:

    var latest=document.getElementById('latest'); var output=document.getElementById('output'); var xhr=new XMLHttpRequest(); open('GET','url_for('stream')}); xhr.send(); var位置=0; 函数handleNewData(){ //响应文本包括到目前为止的整个响应 //拆分消息,然后获取尚未处理的消息 //位置跟踪已处理的邮件数 //消息以换行符结尾,因此split将始终在末尾显示一条额外的空消息 var messages=xhr.responseText.split('\n'); messages.slice(位置,-1).forEach(函数(值){ latest.textContent=value;//就地更新最新值 //生成一个新项并将其附加到列表以记录所有输出 var item=document.createElement('li'); item.textContent=值; 输出。追加子项(项); }); 位置=消息长度-1; } 无功定时器; 计时器=设置间隔(函数(){ //检查新数据的响应 handleNewData(); //响应结束后停止检查 if(xhr.readyState==XMLHttpRequest.DONE){ 清除间隔(计时器); latest.textContent='Done'; } }, 1000);

    可以用来显示流式HTML输出,但它有一些缺点。框架是一个单独的文档,它增加了资源的使用。因为它只显示流数据,所以可能不容易像页面的其余部分那样设置样式。它只能附加数据,所以长时间输出将呈现在可见滚动区域下方。它无法修改页面的其他部分以响应每个事件

    index.html
    使用指向
    端点的框架呈现页面。框架具有相当小的默认尺寸,因此您可能需要进一步设置其样式。使用知道转义变量的
    render\u template\u string
    ,为每个项目呈现HTML(或者使用
    render\u template
    和更复杂的模板文件)。可以产生一个初始行,首先在帧中加载CSS

    从flask导入渲染模板字符串,使用上下文流
    @应用程序路径(“/stream”)
    def stream():
    @流_与_上下文
    def generate():
    生成渲染模板字符串(“”)
    对于范围(500)内的i:
    产生呈现模板字符串(“{{i}}:{{{s}}

    \n”,i=i,s=sqrt(i)) 睡眠(1) 返回app.response_类(generate())
    这是所有的输出:


    5年后,但这实际上可以按照您最初尝试的方式完成,javascript完全没有必要(编辑:在我写这篇文章之后,接受答案的作者添加了iframe部分)。您只需将嵌入输出作为

    从烧瓶导入烧瓶,呈现模板,响应
    输入时间、数学
    app=烧瓶(名称)
    @app.route(“/content”)#将内容呈现为与索引不同的url
    def content():
    def inner():
    #模拟要观看的长过程
    对于范围(500)内的i:
    j=数学sqrt(i)
    时间。睡眠(1)
    #此值应插入到HTML模板中
    收益率str(i)+'
    \n' 返回响应(内部(),mimetype='text/html') @应用程序路径(“/”) def index(): 返回render_template('index.html.jinja')#在索引处呈现模板。内容将嵌入此模板中 app.run(debug=True)
    然后,“index.html.jinja”文件将包含一个
    ,其中的内容url作为src,这可能会
    <!doctype html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <div>
            <iframe frameborder="0" noresize="noresize"
         style='background: transparent; width: 100%; height:100%;' src="{{ url_for('content')}}"></iframe>
        </div>
    </body>