Ajax, Back Button and Dom Updates

Ajax, back button and DOM updates

One answer: Among other things, unload events cause the back/forward cache to be invalidated.

Some browsers store the current state of the entire web page in the so-called "bfcache" or "page cache". This allows them to re-render the page very quickly when navigating via the back and forward buttons, and preserves the state of the DOM and all JavaScript variables. However, when a page contains onunload events, those events could potentially put the page into a non-functional state, and so the page is not stored in the bfcache and must be reloaded (but may be loaded from the standard cache) and re-rendered from scratch, including running all onload handlers. When returning to a page via the bfcache, the DOM is kept in its previous state, without needing to fire onload handlers (because the page is already loaded).

Note that the behavior of the bfcache is different from the standard browser cache with regards to Cache-Control and other HTTP headers. In many cases, browsers will cache a page in the bfcache even if it would not otherwise store it in the standard cache.

jQuery automatically attaches an unload event to the window, so unfortunately using jQuery will disqualify your page from being stored in the bfcache for DOM preservation and quick back/forward. [Update: this has been fixed in jQuery 1.4 so that it only applies to IE]

  • Information about the Firefox bfcache
  • Information about the Safari Page Cache and possible future changes to how unload events work
  • Opera uses fast history navigation
  • Chrome doesn't have a page cache ([1], [2])
  • Pages for playing with DOM manipulations and the bfcache:

    • This page will be stored in the regular cache
    • This page will not, but will still be bfcached

When load page with Ajax, the go back button doesn't works

You've used pushState to add an entry to the browser history, but you haven't added an event handler to determine what happens when the browser navigates back. The browser won't automatically memorise the state of the DOM for you.

Here is a simple example:

<div id="content">1</div>
<button>1</button>
<button>2</button>
<button>3</button>
<button>4</button>

<script>
const div = document.querySelector('div');

addEventListener('click', event => {
if (event.target.tagName.toLowerCase() !== 'button') return;
const last = div.textContent;
const next = event.target.textContent;
div.textContent = next;
history.pushState({ value: next }, `Page ${next}`, `/page/${next}`);
});

addEventListener('popstate', event => {
let state = event.state;
if (state === null) {
// special case: This is the state before pushState was called
// We know what that should be:
state = { value: 1 };
}
div.textContent = state.value;
console.log('location: ' + document.location + ', state: ' + JSON.stringify(event.state));
});
</script>

Preserve DOM changes when back button is used

Options 1, 2, and 5 seems OK. I don't see how the 3rd option could work because the browser does not need to store changes in field values.

So unless you go the single-page-web-application way, like AngularJS, and avoid your navigation problem by not navigating to another page, you need to deal with the browse cache problem. The user could also have clicked a bookmark which is different but similar to the back button problem.

Additionally, not a very strong argument, but if you look at Stack Overflow you can see it uses Cache-Control and ajax requests.

How to mix AJAXy page updates with the Back button so that the updates are still there when the user returns?

Embedding Google Maps into the page disables the bfcache (I'll use the Mozilla term for lack of a standard one) because the maps page loaded in an <iframe> uses an unload listener.

The possible reasons for a page not being cached for fast back navigation in Firefox are listed on MDN: Using Firefox 1.5 caching. Your problem is listed as "the top-level page contains frames that are not cacheable", which is confusing, I'll try to clarify it later. (Other browsers probably use similar heuristics, since these rules were developed to avoid breaking existing content - see also this answer, it has some links.)

The correct way to fix this would be to befriend someone at Google and then nag them until they remove the onunload listener at least from maps' embedded pages.

In general you shouldn't ever rely on bfcache working or not working for a particular page. It's just an optimization for the common case. Since it's an optimization, it could be disabled, for example when the system is low on memory. It also won't work if the user restarts the browser before going back, or closes the tab and picks 'undo close tab', as you noted in the bug.

You should either restore the page's state from JS or mark the page as not cacheable (using an HTTP header). The former results in a better user experience, of course. @Adam Gent's suggestion looks correct, I'll have to check what Firefox problem he refers to.


The reason bfcache works this way is:

  • If the browser runs an onunload handler, then restores the page via bfcache, the page could be broken, since scripts often remove the event listeners in the onunload handler (to "clean up", which is not really necessary except in old IE versions)
  • if the browsers stopped running onunload handlers in a page on the basis that the user might return to the page and they'd like to cache it, the authors would complain.
  • if a page in an iframe can't be cached, restoring a cached outer page and reloading the inner page would break them sometimes (e.g. if both pages are same-domain, the outer page can hold references to objects in the frame, which won't be valid after the inner frame is reloaded). So if an iframe is not cached, neither is the parent page.

The reason the page is still loaded from the (disk) cache when you hit "back" is that presumably you specified that the content you sent to the browser can be cached. The browser has no way to know that you update the page on the server in parallel with making the DOM changes to it.


[edit]I'll elaborate on the "mark the page as not cacheable" idea above. To make web browser cache work for, and not against you, it's important to remember that HTTP is a protocol for retrieving resources. For example, the HTML page identified by the URL http://bbb.akshell.com/broken is a resource. When you serve a resource over HTTP you specify how long the browser's copy of the resource will be valid (i.e. matching the canonical version of the resource on the server).

When, as in your testcase, the resource is an HTML page with the item selected by the user marked up in a special way, the resource may change at any time (every time the user changes the selection). This means that the honest HTTP response when serving this resource would be "don't cache, may change at any time". The browser would then reload the page from the server every time it needs to load the page -- correct behavior, but at the cost of slowness for the user.

An alternative approach, appropriate for things like switching between multiple in-page tabs would be to associate each selection with its own URL. A page with two tabs would correspond to two resources (and two URLs) -- one for each tab. Both resources could be (HTTP-)cached by the browser. Changing the URL and the page's content could be implemented without the roundtrip to the server via pushState.

Another approach, which seems more applicable to your case, in which you save the user's input on the server: separate the app UI and the user's data into different resources (i.e. a static (HTTP-)cacheable HTML page with JS, loading the user data from a separate non-cacheable URL). Request the user data and update the UI on load.[/edit]

Ajax and back button. Hash changes, but where is previous page state stored?

When using AJAX it's important to update the history manually using history.pushState

Then create a function testing for an onpopstate event and updating the content as required.

https://developer.mozilla.org/en-US/docs/Web/Guide/DOM/Manipulating_the_browser_history

Javascript's ajax won't run on browser's back button

the answer is to just add the cache:false, into the ajax script

//
function IncreasePopularity(){
var hiddenid = <?php echo $id; ?>; //$id is the id of the user being rated
$.ajax ({
url: 'IncreasePopularity.php',
data: 'id='+hiddenid,
cache: false,
success: function(data){
alert('haha');
}
});
}


Related Topics



Leave a reply



Submit