如何用Rails与Hotwire Turbo Streaming流式加载长页面?
实现Rails Turbo流式逐条渲染消息
要实现页面加载时每隔100ms显示一条消息,核心是让Rails分块流式输出Turbo Stream内容,而非一次性返回所有渲染结果。以下是两种可行方案:
方案一:整页流式渲染(页面加载时直接输出流)
这种方式在HTML响应中直接流式输出Turbo Stream标签,页面加载过程中浏览器会逐步接收并渲染消息。
1. 修改控制器
启用流式响应,确保Rails分块发送内容:
def index @messages = Message.last(100) # 设置响应类型并开启流式渲染 response.headers['Content-Type'] = 'text/html; charset=utf-8' render stream: true end
2. 修改索引页面模板(index.html.erb)
循环渲染每条消息的Turbo Stream局部视图,每条后添加延迟并立即刷新响应流:
<div id="messages"></div> <% @messages.each do |message| %> <%= render partial: 'message', locals: { message: message } %> <% sleep 0.1 %> <!-- 模拟每条渲染耗时100ms --> <% response.stream.flush %> <!-- 立即发送当前块内容到浏览器 --> <% end %> <% response.stream.close %>
方案二:页面加载后发起流式Turbo请求
先加载空页面,再通过JS发起流式Turbo请求,后台分块返回消息的Turbo Stream内容。
1. 新增控制器动作(或复用现有动作)
专门处理流式Turbo响应:
def stream_messages @messages = Message.last(100) # 设置Turbo Stream响应类型并开启流式渲染 response.headers['Content-Type'] = 'text/vnd.turbo-stream.html; charset=utf-8' render stream: true end
2. 创建Turbo Stream模板(stream_messages.turbo_stream.erb)
分块输出每条消息的Turbo Stream:
<% @messages.each do |message| %> <%= turbo_stream.append :messages, partial: 'message', locals: { message: message } %> <% sleep 0.1 %> <% response.stream.flush %> <% end %> <% response.stream.close %>
3. 修改索引页面模板(index.html.erb)
添加JS在页面加载后发起流式请求,并让Turbo处理返回的流内容:
<div id="messages"></div> <script> document.addEventListener('turbo:load', () => { fetch('/messages/stream', { // 对应stream_messages的路由 headers: { 'Accept': 'text/vnd.turbo-stream.html' } }) .then(response => { const reader = response.body.getReader(); const decoder = new TextDecoder('utf-8'); const processChunk = (result) => { if (result.done) return; // 解码并让Turbo处理当前块的Turbo Stream内容 Turbo.renderStreamMessage(decoder.decode(result.value, { stream: true })); return reader.read().then(processChunk); }; return reader.read().then(processChunk); }); }); </script>
关键说明
- 你现有代码的问题:
turbo_stream.append配合collection会一次性生成所有Turbo Stream标签并返回,浏览器会一次性渲染所有消息,无法实现逐条显示。必须通过response.stream.flush分块发送内容。 - 同步
sleep仅用于简化示例,生产环境建议用异步处理(如Active Job)避免阻塞服务器线程。 - 确保服务器支持流式响应(Puma默认支持,Unicorn需额外配置)。
内容的提问来源于stack exchange,提问作者B Seven
相关产品推荐
相关产品推荐

