As a user, the browser back button is one of the most handy features of a web client. As developers, we wish it never existed.
Using the back button, in it's simplest definition, means to go back to the page we visited before the one we are currently on. But what exactly does this mean?
- Should the browser request the previous page from the server?
- Should it be loaded from the cache?
- Or, should we load some pieces of the page from the server and some from the cache?
In the real world, it depends on the application. One of the most common areas of concern when it comes to the back button is within the shopping cart on e-commerce sites. When a user adds an item to the shopping cart, the number of items in the cart is typically shown in the header of the website, and updated with each item added to the cart.
But, what happens when a user adds an item to the shopping cart, watches the cart count increment by one, then they hit the back button. The cart count will be back to it's original number. This is because the browser has loaded the entire previous page from it's cache.
We're not talking about the browser's usual page cache, where it stores images and scripts in case you visit the website at a later date. This is a dedicated cache which specifically serves back/forward requests. Hence, the back button serves a page that is cached even "stronger" than a normal page cache.
If you're experiencing this issue on your site and think you're the only one, check out Amazon.com. Add an item to the cart, then hit the back button. Yep, it happens to the best of 'em!
Now, after you hit the back button on Amazon's site, hover your mouse over the cart count. You'll notice at that point that the count is updated. This will also happen after a few seconds, once the page has fully loaded.
Amazon uses AJAX to update the shopping cart count. This technique has been around for a long time, and does the job well. But, it does it at the cost of another HTTP call. As there is no direct way to determine when the back button is clicked, that HTTP call needs to be run on every page request.
Luckily, there is another way.
Leverage HTML 5 Storage
We talked about how browsers using a stronger caching mechanism for back/forward operations, which usually involves going beyond storing the HTML, CSS & JavaScript, but actually saving the state of the DOM when the page was left (unloaded). So how do we get around this? Two things make this technique possible:
- Although the JavaScript on the previous page was cached, it is still executed. This means that when the back button is pressed, the JavaScript code itself will be loaded from the browser cache, but it will still be executed by the browser, just as if it came from the server.
- The data in the browser's local and session storage is not cached.
The usual AJAX technique that Amazon.com uses leverages point number 1 above. Because JavaScript is always executed (regardless of where it is loaded from), AJAX calls that are part of that script are executed as well. This allows JavaScript to update any page, even one that was pulled from the browser's back/forward cache.
As you may have guess from reading point number two above, our goal is to replace an AJAX call with a simple read/write to session storage.
I'll present a very specific example that demonstrates this technique. In this example, we're tackling the issue above, where the back button shows an inaccurate shopping cart count.
- When an e-commerce site user adds an item to a shopping cart, they are then directed to the shopping cart page.
- The shopping cart page contains JavaScript which stores the current number of items in the cart to window.sessionStorage.
- All pages except the shopping cart contain JavaScript which retrieves the current number of items from window.sessionStorage.
Example
HTML in the site's header:
<div id="cart"><span id="cart-count">6</span> items</div>
JavaScript (jQuery)
(function() {
var items;
if (typeof Storage !== 'undefined') {
if (location.href.indexOf('/cart') !== -1) {
// on the shopping cart page only, store the text inside
// the cart-count element to sessionStorage
items = $('#cart-count').text();
window.sessionStorage.setItem('cartCount', items);
}
else {
if (sessionStorage.getItem('cartCount')) {
// on all other pages, load the cart count from
// sessionStorage and drop it into the cart-count element
items = window.sessionStorage.getItem('cartItems');
$('#cart-count').text(items);
}
}
}
})();
Nice article
Really ? Doing that when you can just send the proper headers in your scripts so the browser dont cache it ?
Cache-Control: no-cache, must-revalidate
Expires: Sat, 26 Jul 1997 05:00:00 GMT
Why disable caching when a simple update can been state information up-to-date. This is also great for SPA style applications.
Aleksander there are no headers that can stop the cache used for the back button. I encourage you to dive into the details of what the back button does: http://madhatted.com/2013/6/16/you-do-not-understand-browser-history
To Matthews point, right, there’s really no way to “bust” the back button cache. It’s its own animal and uses far stronger caching mechanisms than the browser’s asset cache. The big reason why pressing the back button so quickly loads the page.
You should have a look at the History API (http://diveintohtml5.info/history.html) which is quite useful to tackle those kind of problems.
Didn’t know about the popstate event, good call. We still have much better browser support with sessionStorage at this point though, so I’d say my method is “safer but sloppier!”