Today's Question:  What's your opinion about Alibaba mooncake incident?        GIVE A SHOUT

Technical Article => Web =>  JavaScript

What is pjax and why we should use it?

  sonic0002      2013-04-23 12:22:37      11,420    0    4

What is pjax?

Now many websites such as Facebook, Twitter support one browsing style which is when you click one link on their sites, the page will not be redirected, instead only the page contents are updated and URL on address bar is changed. This kind of user experience is much better compared to load the whole page with a blink.

There is one important component in the above browsing experience, these websites' AJAX refresh support browser history, when refreshing the page, the address on the address bar will also get updated, and when we click back button we can go back to the previous page.

How do we implement this function? Here we introduce one open source project named pjax which can realize this. The project URL is :https://github.com/defunkt/jquery-pjax  The demo page is :http://pjax.heroku.com/ If we don't check the pjax option, then the page will be redirected on clicking the link, after checking that option, the link will change to AJAX refresh.

Why use pjax?

pjax has some advantages:

  • Good user experience

When the whole page is redirected, our eyes will re-checking the new page, while only updating partial page, we only need to check the page which gets updated.

  • Reduce bandwidth and server cost

Since only part of the page is updated, many requests such as CSS/JS requests will not be sent anymore. Although no testings did on how much cost can be saved, the estimation is around 40% and the server cost can be reduced by 30%.

pjax also has some disadvantages:

  • No support of IE6

Since pjax uses the new standard, old browsers may encounter some problems while running pjax. But pjax itself supports fallback, when it finds that the browser doesn't support this function, it will go back to the original redirect way.

  • Complex server side support.

Server side should decide whether a complete page refresh is required or a partial page refresh is required according to the request sent to the server. The server side complexity will be increased, but for the well designed server side codes, it's not a big issue to support this.

How to use pjax?

You can read the official documentation here.

How does pjax work?

pjax only has one source file : https://github.com/defunkt/jquery-pjax/blob/master/jquery.pjax.js.

You can read through all the codes if you want. Here is a brief explanation:

First users should specify what links should use pjax requests and what are the contents to be updated after clicking the links.

$('a[data-pjax]').pjax()

After loading pjax script, it will catch the click event and encapsulate it as an AJAX request and send it to the server:


2
3 4 5 6 7 8 9 10 11 12 13 14 15
$.fn.pjax = function( container, options ) {
  return this.live('click.pjax', function(event){
    handleClick(event, container, options)
  })
}
function handleClick(event, container, options) {
  $.pjax($.extend({}, defaults, options))
  ...
  event.preventDefault()
}
var pjax = $.pjax = function( options ) {
  ...
  pjax.xhr = $.ajax(options)
}

This request has a X-PJAX header parameter, when server receives this request, it will know it only needs to render part of the page.

1
2
xhr.setRequestHeader('X-PJAX', 'true')
xhr.setRequestHeader('X-PJAX-Container', context.selector)

After pjax receives the response from server, it will render the specified area on the page and it will update the address on the address bar as well.

1
2
3
4
5
6
options.success = function(data, status, xhr) {
  var container = extractContainer(data, xhr, options)
  ...
  if (container.title) document.title = container.title
  context.html(container.contents)
}

To support go back function of the browser, it utilizes history API:

1
2
3
4
5
6
7
8
9
10
11
pjax.state = {
  id: options.id || uniqueId(),
  url: container.url,
  container: context.selector,
  fragment: options.fragment,
  timeout: options.timeout
}
if (options.push || options.replace) {
  window.history.replaceState(pjax.state, container.title, container.url)
}

When go back event is triggered, the event will be caught by pjax and it will send one AJAX request:


2
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
$(window).bind('popstate', function(event){
  var state = event.state
  if (state && state.container) {
    var container = $(state.container)
    if (container.length) {
      ...
      var options = {
        id: state.id,
        url: state.url,
        container: container,
        push: false,
        fragment: state.fragment,
        timeout: state.timeout,
        scrollTo: false
      }
      if (contents) {
        // pjax event is deprecated
        $(document).trigger('pjax', [null, options])
        container.trigger('pjax:start', [null, options])
        // end.pjax event is deprecated
        container.trigger('start.pjax', [null, options])
        container.html(contents)
        pjax.state = state
        container.trigger('pjax:end', [null, options])
        // end.pjax event is deprecated
        container.trigger('end.pjax', [null, options])
      } else {
        $.pjax(options)
      }
      ...
    }
  }
}

To support fallback, we need to check whether the browser supports history push state API or not:

 

1
2
3
4
5
// Is pjax supported by this browser?
$.support.pjax =
  window.history && window.history.pushState && window.history.replaceState
  // pushState isn't reliable on iOS until 5.
  && !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/)

The other thing is if there is no response for a long time after a request is sent, it will directly redirect the page:

 

1
2
3
4
5
6
7
8
9
options.beforeSend = function(xhr, settings) {
  if (settings.timeout > 0) {
    timeoutTimer = setTimeout(function() {
      if (fire('pjax:timeout', [xhr, options]))
        xhr.abort('timeout')
    }, settings.timeout)
    // Clear timeout setting so jquerys internal timeout isn't invoked
    settings.timeout = 0

Conclusion

Go and have a try.

AJAX HISTORY PJAX

  SAVE AS PDF   MARK AS READ   MARK AS IMPORTANT

Share on Facebook  Share on Twitter  Share on Google+  Share on Weibo  Share on Reddit  Share on Digg  Share on Tumblr    Delicious

  RELATED


  0 COMMENT


No comment for this article.


  WRITE ARTICLE

After developing a feature alone

By sonic0002