Skip to main content

Pjax (pushState and Ajax)

Free2015-09-22#Front-End#JS#pjax#pushState & Ajax#single page app#spa#pjax详解#pjax原理

What is Pjax, what is it used for, how to use it, and why use it?

I. What is Pjax?

Pjax = history.pushState + Ajax
     = history.pushState + Async JS + XML(xhr?)

The BOM object history has been enhanced, mainly regarding operations on the history stack. Previously, there were only methods like replace and go, which would navigate and refresh the entire page. Now, we have pushState, replaceState, and other methods that simply manipulate the history stack without side effects (the page does not navigate or refresh).

For more information on the history object, please refer to MDN History.

II. What is Pjax used for?

1. The original Single Page Application (SPA)

Page refreshing not only wastes resources (much of the content on sibling pages is the same, so there's no need to reload this repetitive content), but it also impacts user experience (loading, loading, loading...). Partial refreshing can avoid the negative impact of loading on the user experience. Since the concept of Ajax emerged, people started doing this, turning entire sites into Single Page Applications (SPA). Ajax requests JSON, and then the page is partially refreshed to display the data. The original SPA had many drawbacks:

  • The biggest problem: Page content did not match the URL.

This is a fatal flaw. When the content the user sees doesn't match the URL in the address bar, it means the content cannot be easily shared or distributed (and sharing/distribution is crucial). Also, the browser's forward/back buttons cannot work as the user expects.

  • Secondly: It ruins SEO.

SPAs implemented purely with Ajax have a tremendously negative impact on SEO. Because much of the content on the page is rendered by JS after an Ajax request, crawlers cannot see this content, and thus it will not be indexed or included at all.

2. pretty AJAX URL

To solve the SEO problem, Google proposed an ugly method (even though it's called "pretty AJAX URL"...): #!.

It is said that Twitter used it for a month, but later user feedback said it was too ugly, so they stopped using it. This ugly URL did solve the second problem mentioned above, but it required cooperation from search engines. Google recognized this method, so Google's crawler would treat mydomain.com/index.html#!article1 and mydomain.com/index.html#!article2 as two different pages. The server simply had to return the corresponding page for requests to these special URLs, and the SEO problem was solved.

However, the first problem still existed: the page content still didn't correspond to the URL. This led to the creation of Pjax, which we will discuss next.

3. Pjax

W3C introduced a new API that enhanced history's control over the history stack, allowing direct modification of the address bar URL. Only then could page content finally match the URL.

Every time a partial refresh is successful, history.pushState is called to synchronously update the address bar URL (maintaining the history stack). These URLs all correspond to directly accessible pages. Each partial refresh action is triggered by an a tag; JS intercepts the default navigation, uses Ajax to request data, and then displays the data. The user sees a partial refresh and a smooth experience, while the crawler sees normal a tag page navigation. The content displayed on the page is always consistent with the content obtained by directly visiting the URL, so the fatal flaw no longer exists.

If browser support is good, Pjax can perfectly support SPAs. If a browser doesn't support the new API, just treat it like a crawler (currently, there seems to be no good polyfill; even the jq plugin is powerless). As for CSS/JS conflicts, memory leaks, etc., these are issues inherent to SPAs themselves, and mature SPA solutions should be able to avoid them.

III. How to use Pjax?

The core consists of 2 methods and 1 event:

  • history.pushState(state, title, url);

  • history.replaceState(state, title, url);

  • popstate

The state parameter is a custom object that can be retrieved via history.state. The title parameter is largely useless, as browsers generally ignore it. The difference between push and replace is that the former pushes the specified URL onto the stack, while the latter replaces the top element of the stack. The browser's forward/back buttons trigger popstate, where you can handle the UI accordingly based on the history.state data.

There is a relatively concise DEMO from a predecessor: AJAX and HTML5 history pushState/replaceState example.

In addition, there are corresponding open-source libraries available:

  • jQuery's pjax: Still being updated recently (as of 2015-9-22).

  • history.js: Stopped updating 2 years ago, reportedly very easy to use.

  • welefen/pjax: Pjax usage for mainstream JS libraries.

IV. Why use Pjax?

Under the premise of not affecting SEO, partial refreshing + local caching can bring an unprecedented fast experience. This is the absolute advantage of Pjax.

Pjax is suitable for non-pure mobile SPAs, providing a smooth user experience. Moreover, encapsulated Pjax components support additional features like caching, local storage, animations, etc., making them very convenient to use.

Mobile pages generally do not involve frequent large-scale content updates, and they rarely need to consider SEO, so you can just use pure Ajax.

V. Pjax Cases

References

Comments

No comments yet. Be the first to share your thoughts.

Leave a comment