Super Fast Page Loads With PJAX

There’s been a lot of debate in recent years over the merits of building a tried-and-true hybrid client and server UI versus a fully client-side Javascript UI. While client-side Javascript frameworks like Ember.js and Angular.js are getting better almost daily, the hybrid approach is still simpler, easier to build and thus cheaper for most web applications.

The thing is, with the right techniques, you can get really close to the same kind of snappiness as a client-side UI, without all the extra work required to build it.

One of those techniques is PJAX. If you don’t know what PJAX is, it stands for pushState (as in HTML5 pushState) plus AJAX.

The idea is to override link click behavior with Javascript and load only the part of the page that needs updating, replacing it inline without doing a full page refresh. Sounds like AJAX right? Well yes, but then HTML5 pushState is used to replace the browser url, so the browser behaves as though a new url was loaded, preserving back button behavior and the like.

In other words, when you first visit a page, the whole page is loaded including the CSS, Javascripts, images etc. Then when you click a PJAX enabled link for a subpage, it will load only the HTML for that subpage, inserting it into the layout that’s already loaded, ignoring all the wrapper markup like the header and footer, CSS and Javascript includes.

This results in a much snappier page load because its not loading all the extra stuff that’s already loaded. We’ve seen a measurable difference of 2x to 10x faster, but the big win is in the perceived difference. Most of the time, you can’t even tell the difference between a PJAX enabled page load and a fully client-side Javascript UI JSON-only load and re-render.

So how do you do this? The jquery-pjax plugin actually makes this pretty easy.

Once you include jquery-pjax, there’s a few things that need to happen to hook it up.

First, you’ll need to enable the plugin on some or all of the links on the page. Here’s an example that will enable it for all links.

$(document).pjax('a', '#pjax-container')

Now, clicking any link will load HTML from the server and put it into the container #pjax-container.

There’s one more step to this though. We need to tell the server to handle PJAX requests a little differently than normal requests. In a normal request, we would want the server to return a full HTML document. In a PJAX request, we want the server to return only the part of the page unique to this particular link’s URL.

So, in Rails, for example, we’d add this bit to the ApplicationController.

class ApplicationController < ActionController::Base
  layout :determine_layout

  private

  def determine_layout
    request.headers['X-PJAX'] ? false : :application
  end
end

Now, when a PJAX request is made, the server will render the view without a layout.

You’ll notice that this technique requires a server to conditionally assemble the output for a particular URL, so this isn’t really going to work for static websites.

So that introduces PJAX. Next time, I’ll write about another approach we’ve been using when we need a little more control than the jquery-pjax plugin offers using a combination of jQuery and the Backbone.js router.

UPDATE: Here’s a link to the follow up post, Hybrid Routing With Backbone.js.

comments powered by Disqus