History pushState and cache page
Asked Answered
D

1

6

How to cache page loaded via ajax with pushState URL so that reloading page from server can be avoided? For instance,

page 1: /foo.html. click button, send ajax request, get response and update the page. History pushState as a new page /bar.html.

   history.pushState({}, '','/bar.html');

At this point, we like the browser to cache the current page as /bar.html.

window.onpopstate = function(event) {
  // browser is not loading page automatically for back/forward
  if (event.state)
    location.reload();
};

When clicking back/forward button, the /bar.html should be loaded from browser cache. But it is loaded from server again. How to achieve this? that is, let the ajax updated page treated as regular GET /bar.html, and cached by browser. how?

Thanks for any clue. Dave

Dagan answered 18/5, 2014 at 3:5 Comment(16)
“How to achieve this?” – the same way you would achieve it, were AJAX and pushState not involved at all.Torpid
how to tell browser to cache it as new URL? Thanks.Dagan
You simply make your AJAX request again when the user navigates to that history entry again – and if you have implemented proper caching, then the browser will take the data from cache instead of requesting it again.Torpid
set response header Cache-Control: max-age=86400. Chrome/FireFox browser does not cache it. onpopstate: location.reload() always requests the page again from server.Dagan
Well that’s kinda what location.reload() does in reality … but who said anything about using that method in the first place?Torpid
window.onpopstate = function(event) { if (event.state) location.reload(); }; Reload page for browser back/forward button. What is the correct way of doing it? Thanks.Dagan
And why exactly would you do that …?Torpid
Without the onpopstate, the browser will not load the page automatically for back/forward.Dagan
When using the History API, you have to handle what content gets displayed when the user navigates back and forth, that is correct. But nobody is forcing you to do that by reloading the page … You used AJAX already to fetch the content and then put it into the DOM, right? So what is keeping you from doing exactly that again (and thereby making use of the browser’s cache, when it will realize, “hey, I have already loaded that content once before already, so I don’t have to make a new HTTP request here, but I can answer that AJAX request by taking the data out of my cache”) …?Torpid
making use of the browser’s cache? do you mean the browser page caching or web storage in html 5? If the stateObject keeps the ajax response, it still needs the base DOM to update. Where to keep the base DOM? actually need to keep the whole DOM after ajax update somewhere.Dagan
“making use of the browser’s cache?” – well isn’t that what your question is all about? I am talking about the “normal” browser cache for HTTP requests here (as were you before already, with Cache-Control header etcetera). And the DOM for the content loaded via AJAX you will automatically get when making that AJAX request – again … so where’s the actual problem here?Torpid
I edited the post and hope it is easier to understand the issue.Dagan
Not really. And the comment // browser is not loading page automatically for back/forward makes it even more unclear – well isn’t that why you are using the History API in the first place? If you just want the browser to load pages “normally” – then why use the History API, why use AJAX …?Torpid
the best way is to load from browser cache, not from server. I do not know how to make browse cache it as a regular page(GET).Dagan
Mostly by setting appropriate HTTP headers regarding cache behavior – so do some research on that.Torpid
@CBroe I think you might be missing Dave's point. I asked a similar question here: #27357274 , I may be misunderstanding Dave though.Blaze
H
5

If you enable http caching adding the appropriate headers in your responses (Cache-Control, Expires, Last-Modified etc.) then these responses will be stored in cache. There is not one cache. There is the server's cache and downstream caches (ISP, proxies, browser). One of these is the browser's cache.

Suppose that you cache the responses. Have in mind that an http response will be cached no matter its content-type (html, json etc.) So, you load page A, then click on a link that updates the page with ajax and the url with the history api. This is page B. Then you visit page C. The responses A, B and C are stored in browser's cache. But if you go back to page B the browser doesn't automatically load it since you have used the History api for that url. It just updates the url and fires a popstate event.

  1. One approach is to listen to popstate and manually make the same ajax call. Since the response B is already stored in browser's cache, it will be retrieved from there (if it has not been changed in the server).
  2. Another approach would be to store the data retrieved from ajax in an object called state and associate it with the pushed url:

    state = { your_key: your_value }
    history.pushState(state, title, url)
    

    Then on back button catch the popstate event, get its associated state object, access your data and modify the page.

    $(window).on('popstate', function(event) { 
       var state = event.originalEvent.state; 
       if (state) { 
          // use it to modify the page 
       }else{ 
          // ajax call to get the data 
       }
    });
    

    In this case if state exists you don't actually use the browser's cache to retrieve the response.

Have in mind that the state object is stored in client's disk and is of limited size. Thus it is better to store in the state object a reference to the data (for example an id) and store the data itself in memory. This assumes though that you have a Signle Page Application all pages of which are loaded with ajax. (A normal page loading will clear your client's memory)

Homeroom answered 26/1, 2018 at 11:37 Comment(1)
what if i did not actually made an ajax (or any kind of) call for bar.html?Rolland

© 2022 - 2024 — McMap. All rights reserved.