модуль ActionController::Streaming
Позволяет отображать представления на клиенте по мере их рендеринга.
Стандартный способ рендеринга представлений в Rails — сначала рендерить шаблон, а затем макет. Ответ отправляется клиенту после рендеринга всего шаблона, выполнения всех запросов и обработки макета.
Потоковая передача изменяет порядок рендеринга, сначала рендерив макет и передавая каждый фрагмент макета по мере его обработки. Это позволяет быстро передать заголовок HTML (который обычно находится в макете) клиенту, что позволяет загружать JavaScript и стили раньше, чем обычно.
Этот подход был представлен в Rails 3.1 и продолжает совершенствоваться. Некоторые промежуточные программные компоненты Rack могут не работать, и необходимо быть осторожным при использовании потоковой передачи. Эти моменты будут устранены в ближайшее время.
Для использования потоковой передачи потребуется версия Ruby, поддерживающая волокна (fibers поддерживаются с версии 1.9.2 основного реализации Ruby).
Потоковая передача может быть легко добавлена в шаблон, для этого необходимо передать опцию :stream.
class PostsController
def index
@posts = Post.all
render stream: true
end
end
Когда использовать потоковую передачу
Потоковая передача может быть излишней для лёгких действий, таких как new или edit. Реальная выгода от потоковой передачи проявляется в ресурсоёмких действиях, которые, например, выполняют множество запросов к базе данных.
В таких действиях желательно отложить выполнение запросов как можно дольше. Например, представьте следующее dashboard действие:
def dashboard @posts = Post.all @pages = Page.all @articles = Article.all end
Большинство запросов в этом случае выполняется в контроллере. Чтобы использовать преимущества потоковой передачи, его следует переписать следующим образом:
def dashboard # Allow lazy execution of the queries @posts = Post.all @pages = Page.all @articles = Article.all render stream: true end
Обратите внимание, что :stream работает только с шаблонами. Рендеринг :json или :xml с :stream не будет работать.
Взаимодействие между макетом и шаблоном
При использовании потоковой передачи рендеринг происходит сверху вниз, а не изнутри наружу. Rails начинает с макета, а шаблон рендерится позже, когда достигается его yield.
Это означает, что если ваше приложение в настоящее время полагается на переменные экземпляра, заданные в шаблоне, для использования в макете, они не будут работать при переходе на потоковую передачу. Правильный способ взаимодействия между макетом и шаблоном, независимо от того, используете ли вы потоковую передачу или нет, — это использование content_for, provide и yield.
Рассмотрим простой пример, где макет ожидает, что шаблон укажет, какой заголовок использовать:
<html> <head><title><%= yield :title %></title></head> <body><%= yield %></body> </html>
В вашем шаблоне вы бы использовали content_for для указания заголовка:
<%= content_for :title, "Main" %> Hello
И конечный результат будет:
<html> <head><title>Main</title></head> <body>Hello</body> </html>
Однако, если content_for вызывается несколько раз, конечный результат будет содержать все вызовы, соединенные вместе. Например, если у нас есть следующий шаблон:
<%= content_for :title, "Main" %> Hello <%= content_for :title, " page" %>
Конечный результат будет:
<html> <head><title>Main page</title></head> <body>Hello</body> </html>
Это означает, что если у вас yield :title в макете и вы хотите использовать потоковую передачу, вам придется рендерить весь шаблон (и, в конечном итоге, выполнить все запросы) прежде, чем передавать заголовок и все ресурсы, что убивает смысл потоковой передачи. По этой причине Rails 3.1 вводит новый вспомогательный метод provide, который делает то же, что и content_for, но сообщает макету прекратить поиск других записей и продолжить рендеринг.
Например, шаблон выше, использующий provide, будет выглядеть так:
<%= provide :title, "Main" %> Hello <%= content_for :title, " page" %>
Давая:
<html> <head><title>Main</title></head> <body>Hello</body> </html>
Таким образом, при использовании потоковой передачи, необходимо правильно проверить шаблоны и выбрать, когда использовать provide и content_for.
Заголовки, куки, сессия и всплывающие сообщения
При использовании потоковой передачи HTTP-заголовки отправляются клиенту непосредственно перед рендерингом первой строки. Это означает, что изменение заголовков, куки, сессии или всплывающих сообщений после начала рендеринга шаблона не будет передано клиенту.
Промежуточные программные компоненты
Промежуточные программные компоненты, которым нужно манипулировать телом, не будут работать с потоковой передачей. Вы должны отключать эти промежуточные компоненты при использовании потоковой передачи в разработке или в производстве. Например, Rack::Bug не будет работать при использовании потоковой передачи, так как ему необходимо вставлять содержимое в тело HTML.
Также Rack::Cache не будет работать с потоковой передачей, так как пока не поддерживает тела потоковой передачи. При использовании потоковой передачи Cache-Control автоматически устанавливается в значение «no-cache».
Ошибки
При использовании потоковой передачи обработка исключений немного усложняется. Это происходит потому, что часть шаблона уже была рендерирована и передана клиенту, что делает невозможным рендеринг полной страницы ошибки.
В настоящее время, при возникновении исключения в разработке или производстве, Rails автоматически передаст клиенту:
"><script>window.location = "/500.html"</script></html>
Первые два символа («>») необходимы в случае, если исключение возникает во время рендеринга атрибутов для данного тега. Вы можете проверить истинную причину исключения в своём логере.
Поддержка веб-серверов
Не все веб-серверы поддерживают потоковую передачу из коробки. Вам необходимо проверить инструкции для каждого из них.
Unicorn
Unicorn поддерживает потоковую передачу, но требует настройки. Для этого необходимо создать конфигурационный файл следующим образом:
# unicorn.config.rb listen 3000, tcp_nopush: false
И использовать его при инициализации:
unicorn_rails --config-file unicorn.config.rb
Вы также можете настроить другие параметры, например, :tcp_nodelay. Пожалуйста, ознакомьтесь с документацией для получения дополнительной информации: unicorn.bogomips.org/Unicorn/Configurator.html#method-i-listen
Если вы используете Unicorn с Nginx, вам может потребоваться настроить Nginx. Потоковая передача должна работать из коробки с Rainbows.
Passenger
Будет описано позже.
© 2004–2016 David Heinemeier Hansson
Licensed under the MIT License.