🏎️
【Rails】ViewComponentとPartialのパフォーマンスを比較
Railsのpartial
はパフォーマンスを悪化させる、いや本番環境ではそうでもない、view_component
を使うとパフォーマンスがよくなる、いやそうでもない、、
いろんな情報があって、どれが正しいのかわからなかったので、計測してみました。
検証方法
- 直書き、partial、partial(collectionを使った場合)、view componentで同じ内容を出力
- 開発環境でパフォーマンス計測
- 本番環境でパフォーマンス計測
環境構築
$ ruby -v
ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-linux]
$ rails -v
Rails 6.1.3.1
Gemfile
gem "view_component", require: "view_component/engine"
$ bundle install
$ rails g controller samples vanilla partial partial_collection view_component
$ rails g model sample name:string
$ rails db:migrate
app/controllers/samples_controller.rb
class SamplesController < ApplicationController
before_action :build_samples
def vanilla
end
def partial
end
def partial_collection
end
def view_component
end
def build_samples
@samples = Sample.all
end
end
db/seed.rb
100.times do |n|
Sample.create!(name: "ホゲホゲ#{n}")
end
$ rails db:seed
vanilla
app/views/samples/vanilla.html.erb
<% @samples.each do |sample| %>
<p><%= sample.name %></p>
<% end %>
partial
$ touch app/views/samples/_hoge.html.erb
app/views/samples/_hoge.html.erb
<p><%= hoge.name %></p>
app/views/samples/partial.html.erb
<% @samples.each do |sample| %>
<%= render 'hoge', hoge: sample %>
<% end %>
partial(collection)
app/views/samples/partial.html.erb
<%= render partial: 'hoge', collection: @samples, as: 'hoge' %>
view_component
$ rails g component Hoge hoge
app/components/hoge_component.rb
class HogeComponent < ViewComponent::Base
def initialize(hoge:)
@hoge = hoge
end
end
app/components/hoge_component.html.erb
<p><%= @hoge.name %></p>
app/views/samples/hoge_component.html.erb
<% @samples.each do |sample| %>
<%= render(HogeComponent.new(hoge: sample)) %>
<% end %>
計測
samples/vanilla
、samples/partial
、samples/view_component
にアクセスし、ログの以下の箇所を確認。
ローカル
それぞれ5回ずつアクセスし、中央値を記録。
結果 | |
---|---|
vanilla | 8.7ms |
partial | 23.3ms |
partial_collection | 8.5ms |
view_component | 9.2ms |
本番
それぞれ11回ずつアクセスし、中央値を記録。
サーバーはHeroku。
結果 | |
---|---|
vanilla | 5.3ms |
partial | 10.7ms |
partial_collection | 4.45ms |
view_component | 5.55ms |
まとめ、感想
- eachで回して使う分には、本番でもローカルでも、partialよりview_componentの方が2倍くらいパフォーマンスが良い
- 逆に100回partialを呼んでも2倍程度しか変わらないなら、5回10回のpartialの呼び出しに神経質にならなくてもいい?
- 今回は同じpartialを100回呼んだけど、違うパーシャルを呼ぶ場合はまた話が違うのかも
- ローカルでも本番でも、直書きよりpartial_collectionの方がパフォーマンスが良かった。
- 直書きの場合「何件あるか?」ってことを考えずに直列に実行するけれど、render collectionを使った場合は予め件数を数えてから、先に文字列を件数分作ってそれに必要なキーを当てはめていくから文字列生成コストの面でパフォーマンスが良いっぽい
- https://api.rubyonrails.org/classes/ActionView/PartialRenderer.html#method-i-render
- view_componentはeachで回してもパフォーマンスの劣化が最小限だった
- パフォーマンスだけじゃなくて、テストが書きやすくなるなどのメリットもあるので、基本的な方針としてはview_componentを優先して使う感じが良さそう。
参考
Discussion