ruby-on-rails - Rails、JSON 和加载时间

标签 ruby-on-rails json ruby-on-rails-3.2

我的 rails 应用程序在加载 JSON 数据时遇到了一些加载时间问题,我从 URL 源加载 JSON 数据,然后使用 lazy_high_charts gem 将其解析为图形。目前每次加载页面需要 7 - 10 秒。

我有三个 JSON 数据 URL(@data、@forecast、@moisture),它们使用 Oj gem 进行解析,因为有人建议它会加快进程。

如果可能的话,我正在寻找一种方法来加速这个过程。

JSON 数据结构如下:

{"status"=>"ok", "data"=>[{"2014-08-11 11:00:00"=>14.9},{"2014-08-11 11:30:00"=>15.1}]}

Controller
@temperature = Temperature.find(params[:id])
@temps = Temperature.find(:all, :conditions => ["id != ?", params[:id]])

@hash = Gmaps4rails.build_markers(@temperature) do |data, marker|
 marker.lat data.lat
 marker.lng data.long
end

@data =  Oj.load(open(@temperature.url).read)
@forecast =  Oj.load(open(@temperature.air_forecast).read)
@moisture =  Oj.load(open(@temperature.moisture).read)

data = []
moisture = []
forecast = []

@data['data'].flatten.each do |d|
 data << [DateTime.parse(d.keys.first).to_i * 1000, d.values.first]
end    

@moisture['data'].each do |d|
 moisture << [DateTime.parse(d.keys.first).to_i * 1000, d.values.first]
end 

@sevendays = LazyHighCharts::HighChart.new('graph') do |f|
 f.chart(:height => '400', width: '860', plotBackgroundImage: ActionController::Base.helpers.asset_path("chartbg.png"))
 f.yAxis [:title => {:text => "Soil Temperature (\u00B0C)", :margin => 20, style: { color: '#333'}}, min: 0, plotLines: [{ color: '#b20838', width: 2, value: 28 }], ]
 f.series(:type => 'line', :name => 'Soil Temperature', data: data, marker: {enabled: false}, :color => '#00463f' )
 f.xAxis(:type => 'datetime', tickInterval: 1.day.to_i * 1000, :dateTimeLabelFormats => { day: "%b %e"}, :tickmarkPlacement => 'on', :startOnTick => true, min: 1.weeks.ago.at_midnight.to_i * 1000, labels: { y: 20 } )
 f.legend({:align => 'center', :verticalAlign => 'top', :y => 0, :borderWidth => 0, style: {color: "#333"}})
end

@day = LazyHighCharts::HighChart.new('graph') do |f|
 f.chart(:height => '400', width: '860', plotBackgroundImage: ActionController::Base.helpers.asset_path("chartbg.png"))
 f.yAxis [:title => {:text => "Soil Temperature (\u00B0C)", :margin => 20, style: { color: '#333'}}, min: 0, plotLines: [{ color: '#b20838', width: 2, value: 28 }]]
 f.series(:type => 'line', :name => 'Soil Temperature', data: data, marker: {enabled: false}, :color => '#00463f' )
 f.xAxis(:type => 'datetime', tickInterval: 5.hour.to_i * 1000, :dateTimeLabelFormats => { day: "%b %e"}, :tickmarkPlacement => 'on', :startOnTick => true, min: 1.day.ago.at_midnight.to_i * 1000, labels: { y: 20 } )
 f.legend({:align => 'center', :verticalAlign => 'top', :y => 0, :borderWidth => 0, style: {color: "#333"}})
end

@month = LazyHighCharts::HighChart.new('graph') do |f|
 f.chart(:height => '400', width: '860', plotBackgroundImage: ActionController::Base.helpers.asset_path("chartbg.png"))
 f.yAxis [:title => {:text => "Soil Temperature (\u00B0C)", :margin => 20, style: { color: '#333'}}, min: 0, plotLines: [{ color: '#b20838', width: 2, value: 28 }]]
 f.series(:type => 'line', :name => 'Soil Temperature', data: data, marker: {enabled: false}, :color => '#00463f' )
 f.xAxis(:type => 'datetime', tickInterval: 2.day.to_i * 1000, :dateTimeLabelFormats => { day: "%b %e"}, :tickmarkPlacement => 'on', :startOnTick => true, min: 1.month.ago.at_midnight.to_i * 1000, labels: { rotation: 90, y:20 })
 f.legend({:align => 'center', :verticalAlign => 'top', :y => 0, :borderWidth => 0, style: {color: "#333"}})
 f.plotOptions({line: {turboThreshold: 1500}})
end

@moisture_graph = LazyHighCharts::HighChart.new('graph') do |f|
 f.chart(:height => '400', width: '860', plotBackgroundImage: ActionController::Base.helpers.asset_path("chartbg.png"))
 f.yAxis [:title => {:text => "Litres of Water Per Litre of Soil", :margin => 20, style: { color: '#333'}}]
 f.series(:type => 'line', :name => 'Surface Moisture Volume', pointInterval: 1.day * 1000, data: moisture, marker: {enabled: false}, :color => '#00463f' )
 f.xAxis(:type => 'datetime', tickInterval: 1.day.to_i * 1000, :dateTimeLabelFormats => { day: "%b %e"}, :tickmarkPlacement => 'on', :startOnTick => true, min: 1.weeks.ago.at_midnight.to_i * 1000, labels: { y: 20 } )
 f.legend({:align => 'center', :verticalAlign => 'top', :y => 0, :borderWidth => 0, style: {color: "#333"}})
end

respond_to do |format|
 format.html # show.html.erb
 format.json { render json: @temperature }
end
end

看法
<ul class="nav nav-pills">
 <li class="active"><a href="#seven" data-toggle="tab">Last 7 Days</a></li>
 <li><a href="#forecast" data-toggle="tab">7 Day Forecast Temperature</a></li>
 <li><a href="#day" data-toggle="tab">Last 24 Hours</a></li>
 <li><a href="#month" data-toggle="tab">Last 30 Days</a></li>
 <li><a href="#moisture" data-toggle="tab">Surface Moisture Volume</a></li>
 <li><a href="#location" data-toggle="tab">Location of <%= @soil_temperature.property %></a></li>
</ul>

<div class="tab-content">

    <div class="tab-pane active" id="seven" style="width: 100%;">
        <%= high_chart("chart", @sevendays) %>
    </div>

    <div class="tab-pane" id="forecast" style="width: 100%;">
        <table class="table table-bordered table_forecast" width="100%">
            <th></th>
            <% Time.use_zone('Sydney'){(0.day.from_now.to_date..6.day.from_now.to_date)}.each do |d| %>
            <th><%= d.strftime("%a %d, %b") %></th>
            <% end %>
            <tr>
            <td width="12.5%"><b>Maximum</b></td>
            <% Time.use_zone('Sydney'){(0.day.from_now.to_date..6.day.from_now.to_date)}.each do |d| %>
            <% if @forecast['data']['temperatures'].select { |temp| temp[0].to_date == d }.max { |a,b| a[1] <=> b[1] }[1] > 20 %>
            <td width="12.5%" bgcolor="#ed1c24"><font color="#ffffff">
            <% elsif @forecast['data']['temperatures'].select { |temp| temp[0].to_date == d }.max { |a,b| a[1] <=> b[1] }[1] > 14 %>
            <td width="12.5%" bgcolor="#f58233"><font color="#fff">
            <% elsif @forecast['data']['temperatures'].select { |temp| temp[0].to_date == d }.min { |a,b| a[1] <=> b[1] }[1] < 14 %>
            <td width="12.5%" bgcolor="#00a1e4"><font color="#fff">
            <% else %>
            <td width="12.5%"><font color="#333333">
            <% end %>
            <%= @forecast['data']['temperatures'].select { |temp| temp[0].to_date == d }.max { |a,b| a[1] <=> b[1] }[1] %>°C</font></td>
            <% end %>
            </tr>
            <tr>
            <td width="12.5%"><b>Minimum</b></td>
            <% Time.use_zone('Sydney'){(0.day.from_now.to_date..6.day.from_now.to_date)}.each do |d| %>
            <% if @forecast['data']['temperatures'].select { |temp| temp[0].to_date == d }.min { |a,b| a[1] <=> b[1] }[1] > 20 %>
            <td width="12.5%" bgcolor="#ed1c24"><font color="#ffffff">
            <% elsif @forecast['data']['temperatures'].select { |temp| temp[0].to_date == d }.min { |a,b| a[1] <=> b[1] }[1] > 14 %>
            <td width="12.5%" bgcolor="#f58233"><font color="#fff">
            <% elsif @forecast['data']['temperatures'].select { |temp| temp[0].to_date == d }.min { |a,b| a[1] <=> b[1] }[1] < 14 %>
            <td width="12.5%" bgcolor="#00a1e4"><font color="#fff">
            <% else %>
            <td width="12.5%"><font color="#333333">
            <% end %>
            <%= @forecast['data']['temperatures'].select { |temp| temp[0].to_date == d }.min { |a,b| a[1] <=> b[1] }[1] %>°C</td>
            <% end %>
            </tr>
            <tr>
            <td width="12.5%"><b>Average</b></td>
            <% Time.use_zone('Sydney'){(0.day.from_now.to_date..6.day.from_now.to_date)}.each do |d| %>
            <% if (@forecast['data']['temperatures'].select { |temp| temp[0].to_date == d }.sum { |sum| sum[1] } / @forecast['data']['temperatures'].select { |temp| temp[0].to_date == d }.count) > 20 %>
            <td width="12.5%" bgcolor="#ed1c24"><font color="#ffffff">
            <% elsif (@forecast['data']['temperatures'].select { |temp| temp[0].to_date == d }.sum { |sum| sum[1] } / @forecast['data']['temperatures'].select { |temp| temp[0].to_date == d }.count) > 14 %>
            <td width="12.5%" bgcolor="#f58233"><font color="#fff">
            <% elsif (@forecast['data']['temperatures'].select { |temp| temp[0].to_date == d }.sum { |sum| sum[1] } / @forecast['data']['temperatures'].select { |temp| temp[0].to_date == d }.count) < 14 %>
            <td width="12.5%" bgcolor="#00a1e4"><font color="#fff">
            <% else %>
            <td width="12.5%"><font color="#333333">
            <% end %>
            <%= "%.1f" % (@forecast['data']['temperatures'].select { |temp| temp[0].to_date == d }.sum { |sum| sum[1] } / @forecast['data']['temperatures'].select { |temp| temp[0].to_date == d }.count) %>°C</td>
            <% end %>
            </tr>

        </table>
    </div>

    <div class="tab-pane" id="day" style="width: 100%;">
        <%= high_chart("chart2", @day) %>
    </div>

    <div class="tab-pane" id="month" style="width: 100%;">
        <%= high_chart("chart3", @month) %>
    </div>

    <div class="tab-pane" id="moisture" style="width: 100%;">
        <%= high_chart("chart4", @moisture_graph) %>
    </div>

    <div class="tab-pane" id="location" style="width: 100%;">
        <div id="map" style='width: 100%; height: 600px;'></div>
    </div>
    <hr>

</div>

<script type="text/javascript">

    $('a[href="#location"]').on('shown', function(e) {
    var mapOptions = { mapTypeId: google.maps.MapTypeId.HYBRID, Zoom: 9 };
    handler = Gmaps.build('Google');
    handler.buildMap({ provider: mapOptions, internal: {id: 'map'}}, function(){
    markers = handler.addMarkers(<%= raw @hash.to_json %>);
    handler.map.centerOn(markers[0]); 
    handler.getMap().setZoom(9);
    google.maps.event.trigger(map, "resize");
    });
  });

</script>

最佳答案

听起来好像“URL 源”正在提供来自第三方站点的天气预报信息。 URL 本身是否需要 7-10 秒才能加载?如果是这样,您可能几乎无能为力来加速它们。即使是并行请求也只会与最快的请求一样快。相反,您可以尝试移动延迟,以便最终用户不会体验到它。

据推测,此信息不会每分钟都发生显着变化。如果您的潜在预测位置数量有限,您可以尝试预先加载和存储数据。特别是,您可以使用 cron 作业每 X 分钟提取一次数据并将其存储在您的数据库中,您可以在其中在页面加载时查询它。

或者,您可以加载没有数据的页面(显示一个简单的“正在加载...”文本),然后通过 Ajax 用数据填充它。这不会使查看数据的速度更快,但它会提供比盯着空白页面 7-10 秒更好的用户体验。

关于ruby-on-rails - Rails、JSON 和加载时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31418640/

相关文章:

ruby-on-rails - 如何处理来自 Rails 应用程序的带有多个大附件的传入电子邮件?

ruby-on-rails - 使用 rails-i18n 进行反向翻译

ruby-on-rails - 在 ruby​​ on Rails 中将参数作为路径变量传递

javascript - 无法在 Angular.js 中使用检索到的 JSON 对象

ruby-on-rails-3 - 发现(:first) and find(:all) are deprecated

json - 在rails中使用CoffeScript检索json数据

ruby-on-rails - Jekyll 安装失败

javascript - 在 json 对象数组中查找一个键值,并使用 Angular 返回另一个键值

ios - JSON 对象映射 - RestKit

ruby-on-rails - RubyMine 显示错误消息 : "Error running Development: MyProject: Rails 3.x launcher script was found instead of Rails 4.x one"