How to speed up your AngularJS + Rails app by reducing HTTP Calls

By default, AngularJS sites are slower than they need to be. Most AngularJS sites are bogged down with multiple HTTP calls on the initial page load. Multiple HTTP calls result in slower response time, and higher heroku bills. Sites that load slow can see users flee your site, especially on Mobile connections.

Imagine your site responding as fast as possible, with fast load times, and impressive interactivity. Speed is a feature, nay, THE Feature of your site, and you want to do everything you can to make a speedy first impression for your visitors.

The easiest way to speed up your site with the minimal investment of your time is to reduce the number of HTTP calls from your site to a server, each of which slow down your site (Yahoo 2006). HTTP call reduction 'is the most important guideline for improving performance for first time visitors'.

AngularJS apps have two low hanging, easy wins for reducing HTTP calls: ng-init for preloading JSON, and preloading your templates using the asset pipeline.

Preload JSON with AngularJS

In most applications, the very first thing your app does is fetch data, using a pattern similar to the following:

YourApp.controller "SuperFun", ($scope, $http) ->
  fetchRecords = () ->
    $http.get('/records')
    .success (data) ->
      $scope.records = data
 ng-controller='SuperFun' ng-init='fetchRecords()'>

This loads your page and kicks off an HTTP request. The AJAX request has to connect with your Rails instance, parse its response, add it to the scope, and then render the records. Slow!

Instead, you want to pass JSON into your ng-init from Rails (hopefully caching it there). That'll look like:

 ng-controller='SuperFun' ng-init='setRecords(<%= json_for(@records))'>
YourApp.controller "SuperFun", ($scope) ->
  setRecords = (records) ->
    $scope.records = data
  1. Add to your Gemfile: gem active_model_serializers
  2. run bundle.
  3. run $ rails g serializer record
  4. In your Rails application_helper.rb RailsCast Credit
     def json_for(target, options = {})
       options[:scope] ||= self
       options[:url_options] ||= url_options
       target.active_model_serializer.new(target, options).to_json
     end
    
  5. In your Rails controller
    class AngularController < ApplicationController
     def show
       @records = Record.all
     end
    end
    
  6. Restart your Rails instance

BAM! no more AJAX data requests. Your pages will load noticeably faster.

Preload Templates with Rails Asset Pipeline

When your AngularJS app reaches a certain size, you'll likely move to using routes, which load HTML templates. Continuing our example, you might first show a list of records, and when clicked, transfer the user to a record detail page. You might add a routes file, and following most examples, it'll look something like this:

YourApp.config ($routeProvider, $locationProvider) ->
  $routeProvider
    .when "/",
      templateUrl: "../../assets/records/list.html"
      controller: "DashboardController"
    .when "/records/:uid",
      templateUrl: "../../assets/records/detail.html"
      controller: "RecordsController"
    .otherwise redirectTo: "/"
  $locationProvider.html5Mode(true)

The template URL is a location for AngularJS to pull the HTML. So, before it can use the template to List, it needs to make an HTTP request, interpret it into JavaScript, and run the AngularJS commands you've added to it.

Instead, we can compile these templates into the Rails asset pipeline JST, using the ECO gem.

  1. add gem 'eco' to your Gemfile and run bundle
  2. Move your templates into app/javascripts/angular/templates
  3. Rename the templates to detail.jst.eco, and use them the exact same way as HTML.

Finally, change your routes file to:

YourApp.config ($routeProvider, $locationProvider) ->
  $routeProvider
    .when "/",
      template: JST['angular/templates/records/list']
      controller: "RecordsController"
    .when "/records/:uid",
      template: JST['angular/templates/records/detail']
      controller: "RecordsController"
    .otherwise redirectTo: "/"
  $locationProvider.html5Mode(true)

The result? Your application.js has access to a compiled version of the templates in the global JST variable. AngularJS pulls from there instead of making an HTTP call.

Net Result

With these two easy optimizations, your app will be faster, more responsive -- definitely major wins your app.

These optimizations are exactly what we go over, with working code you can use in your apps, at http://angularails.com.

Want More AngularJS + Rails?

We'll send you more articles like this, plus information about the online workshop. We will never SPAM you.