与Sinatra一起流,逐渐更新目的地

时间:2012-06-05 18:51:33

标签: javascript sinatra

我有一个Sinatra网络应用程序,我非常希望通过某些功能的流式更新来增强。但是现在,我只是想学习使用流数据的方法,这是我以前从未做过的。我有以下简单的测试代码:

在Sinatra:

get '/foo' do
  stream do |out|
    10.times do
      out.puts "foo"
      out.flush
      sleep 1
    end
  end
end

get '/bar' do
  erb :bar
end

bar.erb

<body>
  <div class="stream">
    nothing.
  </div>
</body>

<script type="text/javascript" charset="utf-8">
  $(document).ready( function() {
    $.get('/foo', function(html) {
      $(".stream").html(html);
    });
  });
</script>

我并不感到惊讶,这不是我想做的,也就是在写入时每个'foo'并动态更新页面。相反,没有任何事情发生约10秒然后我得到foo foo foo foo foo foo foo foo foo foo foo

我的问题是,如何在ERB模板中(使用Ruby,jQuery或其他方法)如何提取流式数据,而不是阻塞,直到它全部收集并立即全部吐出?

2 个答案:

答案 0 :(得分:5)

Sinatra操作包装整个HTTP响应周期 - 这意味着它会在关闭请求之前等待操作完成,此时浏览器会认为数据“完整”且“正常”可供使用。您在上面的代码中创建的所有内容都是非常非常慢的Sinatra操作。

您正在寻找的技术是Websockets,它受大多数现代浏览器的支持,并在每个客户端和服务器之间提供双向通信通道。 websocket通道是通过“升级”常规HTTP请求来创建的。在客户端不支持Web套接字的情况下,可以使用诸如HTTP Long Polling(其中请求保持打开,没有响应,直到有可用数据)等技术来模拟它们,此时数据被分流到响应通道,响应通道已关闭,客户端需要打开一个新请求以获取更多数据。)

您可以使用EventMachine和EM-Websocket在Ruby应用中设置此设置。另一种选择是Socky我认为它提供了javascript客户端以及Ruby服务器。

答案 1 :(得分:0)

如果您在Sinatra中使用流,则跳过普通模板,您将获得一个空白页面,其中只包含您正在流式传输的HTML。 您可以通过手动创建和流式传输布局以及文本来避免这种情况。这是一个例子。

require 'sinatra'
require "sinatra/streaming"
set server: 'thin', connections: []

get '/' do
  stream do |out|
    settings.connections << out
    @out = out
    erb :stream
    out.callback { settings.connections.delete(out) }
  end
end
__END__
@@pre
  <!DOCTYPE html>
  <html>
  <head>
    <title>test</title>
  </head>
  <body>
   <h1>This is the body</h1>

@@after
  </body>
  </html>

@@stream
  <%
    @out.puts erb(:pre)
    @out.puts "<h2>test</h2>"
    (1..10).each do |i|
        @out.puts "#{i}<br>"
        sleep 2
      end
    @out.puts erb(:after)
    @out.flush
  %>