|Posted by kyle on April 11, 2010 1:59 PM||bookmark / share:|
Web Apps and History
Web applications need to interact with the browser history to support bookmarkable and "back-buttonable" states. This is a pretty common feature of Ajaxy applications. For example, visit http://www.viewru.com/#Bonobo and browse or search for your favorite musician. The application uses an Ajaxy, single-window-context model to keep the music playing while you browse, but supports bookmarks and the back-button because users expect these features to work in their browser.
Prior to the HTML5 History additions, a solution to this problem involved these two parts:
The solution is less than ideal for several reasons:Sluggishness
- Executing a timeout function every 100ms won't make your app any faster.
- 100ms delay in responding to back button actions.
- The solution above doesn't work, for example, in IE 6-7, which won't add a history event on a hash change. Really Simple History gets around this by adding an iframe and issuing a call to your server for every state change. Webkit browsers present different challenges.
Not a stack
- Suppose your application transitions from A->B->C. Can it transition directly back to A?
The HTML5 version looks like this:
Here, state may be a string representation of the current application state, but it can also be an object. Note that it will be deep-copied on each pushState() operation.
Storing application state in the hash is a hack
You may point out that the new hashchange event in HTML5 addresses concerns about sluggishness, but why use location.hash at all? Storing application state in the location hash presents some real problems and limitations. Here's a short list:
- Audible "click" in IE: For some reason, IE makes a sound every time you update the location. Imagine if your application updated the location on every mousemove event!
- HTTP-Referer is inaccurate or missing data: The fragment ID isn't exposed in the referrer.
- Handling bookmarks requires extra round trip:
- Fetch myApp.html
- Parse myApp.html#myState (server can't see myState)
- Fetch myState
- Legacy (and non-JS) browsers effectively have different URI schemes and can't share bookmarks and links.
HTML5 History and URLs
Perhaps the most interesting feature of the new pushState() and replaceState() interfaces is the optional url argument. For the first time, web developers are able to change the effective URL to represent a change in application state without navigating away from a window context. It's very powerful. The location bar, bookmark service, and HTTP-Referer all reflect the new URL. This feature addresses many of the issues I mentioned above:
- Content is crawlable: A developer may express all crawlable states of their application as valid URLs.
- HTTP-Referer is meaningful: The referrer can reflect the latest state of the application and show or hide any information to/from 3rd parties, at the developer's discretion.
- Bookmarks can be handled in a single fetch: Since application state can be expressed in a URL, it's possible to service a request for the application and state in one request/response.
- Can use a single URI scheme to cover new and old browsers: Since information is encoded in URLs instead of the location hash, modern and legacy users can share bookmarks and links.
- Audible "click" in IE? Okay, I don't know about this one, but it makes sense that programmatic operations on window.history would not have an audible side effect, right?
Availability and further reading
You can take these new features for a spin in Firefox nightlies. For more info, see: