94

When I use the back button on Firefox to reach a previously visited page, scripts on that page won't run again.

Is there any fix/workaround to have the scripts execute again when viewing the page the second time?

Please note that I have tested the same pages on Google Chrome and Internet Explorer and they work as intended.


Here are the files and the steps I used to test the problem:

(navigate to 0.html, click to get to 1.html, back button)

0.html

<html><body>
<script>
  window.onload = function() { alert('window.onload alert'); };
  alert('inline alert');
</script>
<a href="1.html">Click Me!</a>
</body></html>

1.html

<html><body>
<p>Go BACK!</p>
</body></html>
Volker E.
  • 5,911
  • 11
  • 47
  • 64
Patonza
  • 6,557
  • 5
  • 25
  • 20

8 Answers8

101

Set an empty function to be called on window.onunload:

window.onunload = function(){}; 

e.g.

<html><body>
<script type="text/javascript">
  window.onload = function() { alert('window.onload alert'); };
  window.onunload = function(){};
  alert('inline alert');
</script>
<a href="1.html">Click Me!</a>
</body></html>

Source: http://www.firefoxanswer.com/firefox/672-firefoxanswer.html (Archived Version)

John Baber-Lucero
  • 2,556
  • 3
  • 16
  • 19
  • 2
    Thank you, it works. Any hint on what does the default onunload handler do? (e.g. am I overriding a default behaviour of some sort here?) – Patonza Apr 14 '10 at 14:55
  • Ok thanks, I'll investigate. Thank you again, this problem has been haunting me for a while :) – Patonza Apr 14 '10 at 15:01
  • anybody know why FireFox needs this while other browsers do not? – Pim Jager Apr 14 '10 at 15:12
  • 8
    You're not overriding anything, this just prevents Firefox from caching the page in the Back-Forward Cache (bfcache). https://developer.mozilla.org/en/DOM/window.onunload https://developer.mozilla.org/En/Using_Firefox_1.5_caching – Chris Haas Apr 14 '10 at 15:34
  • www.firefoxanswer.com link is dead, but @Chris's link works - https://developer.mozilla.org/en/DOM/window.onunload lists the reason in the Notes section – mlhDev Dec 19 '12 at 12:58
  • 1
    While it *should* break bfcache unfortunately it seems it still remembers the previous page - specifically, iframe urls that were loaded are loaded again when you go back, and if generated content needed to be placed in the frame, there doesn't seem to be crossbrowser way to refresh that anew. – NoBugs Jan 20 '15 at 16:06
  • if you use jQuery, I suggest to use $(window).on('unload', function() {}); – Alex Jun 29 '16 at 12:58
  • In MDN, unload is [documented](https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onunload) to prevent this caching only with Firefox 1.5 (and not in all pages about it), while [beforeunload](https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event) is documented as preventing this caching without mentionning a specific browser version. So currently it seems better to use `beforeunload` if you want to use this hack instead of this [solution](/a/2639165/1178314). – Frédéric Nov 26 '19 at 18:07
  • Keep in mind onunload generally isn't good for mobile as many (most?) mobile browsers don't actually fire that anymore. Consider instead the Page Visibility API. Here's a short explanation I find useful: https://www.igvita.com/2015/11/20/dont-lose-user-and-app-state-use-page-visibility/ (if you're not concerned with mobile, you're probably not doing it right...). Also, +1 for proposing a non-jQuery solution. – Carnix Jun 07 '21 at 16:12
77

When I use the back button on Firefox to reach a previously visited page, scripts on that page won't run again.

That's correct and that's a good thing.

When you hit a link in Firefox (and Safari, and Opera), it does not immediately destroy your page to go onto the next one. It keeps the page intact, merely hiding it from view. Should you hit the back button, it will then bring the old page back into view, without having to load the document again; this is much faster, resulting in smoother back/forward page transitions for the user.

This feature is called the bfcache.

Any content you added to the page during the user's previous load and use of it will still be there. Any event handlers you attached to page elements will still be attached. Any timeouts/intervals you set will still be active. So there's rarely any reason you need to know that you have been hidden and re-shown. It would be wrong to call onload or inline script code again, because any binding and content generation you did in that function would be executing a second time over the same content, with potentially disastrous results. (eg. document.write in inline script would totally destroy the page.)

The reason writing to window.onunload has an effect is that the browsers that implement bfcache have decided that — for compatibility with pages that really do need to know when they're being discarded — any page that declares an interest in knowing when onunload occurs will cause the bfcache to be disabled. That page will be loaded fresh when you go back to it, instead of fetched from the bfcache.

So if you set window.onunload= function() {};, what you're actually doing is deliberately breaking the bfcache. This will result in your pages being slow to navigate, and should not be used except as a last resort.

If you do need to know when the user leaves or comes back to your page, without messing up the bfcache, you can trap the onpageshow and onpagehide events instead:

window.onload=window.onpageshow= function() {
    alert('Hello!');
};
Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
bobince
  • 528,062
  • 107
  • 651
  • 834
  • 4
    My problem is that bfcache does not cache ALL the page so I have to re-run js to rebuild lost content. So thrashing the whole page could be ok. Anyway, I'm not using the window.onload event, I'm using jQuery document.ready event. Do you know a way to still be able to use document.ready and avoid this problem? – Patonza Apr 15 '10 at 10:07
  • bfcache should in general return the entire page as it was when it was left. What is the content that's missing after returning from the previous page? (test case?) `document.ready` will work essentially in the same way as `window.onload` (for some browsers, they are the same event anyway). – bobince Apr 15 '10 at 11:14
  • 14
    That is NOT a good thing because it doesn't run the javascript again, considering it cached...but DOESN'T actually cache the changes the javascript had made previously. If the javascript fades in an element on page load, it doesn't fade it it again when visiting in history...but DOES start it on 0 opacity again, undoing what the javascript had done! It has to be ALL OR NOTHING. You must cache the complete state of the page after the javascript has run if you want to present it cached without running the javascript again! – Jimbo Jonny Dec 18 '12 at 18:15
  • 1
    @Jimbo: Test case please. bfcache is intended to (and in every case I have ever seen, does) preserve the exact state of the DOM over hide/show. An element that had been faded in will remain opaque when the page is returned to, unless some other script runs to hide it again. – bobince Dec 19 '12 at 10:01
  • 1
    @bobince - Make an element with a CSS file setting the opacity to zero and then use some jQuery to make it fade in on the document ready. Upon going back in history it will reapply the stylesheet CSS (the zero) without keeping the opacity:1 that the JS added to the style attribute when fading it in. First time you visit the page the element will fade in from zero to 1. Go to another page and hit back and it will just sit there fully transparent. – Jimbo Jonny Dec 28 '12 at 19:33
  • @Jimbo: Works for me - http://fiddle.jshell.net/h9ap6/1/show/light/ . CSS doesn't work the way you imply. Stylesheets are constantly, dynamically applied to the rendered form of a document. They do not affect the actual DOM at all; the inline 'style' property of a specific element is never touched by an application of stylesheet rules and there is no 're-application' at page show time. – bobince Dec 28 '12 at 22:16
  • @bobince - That's not how I implied CSS works. I said since it did not keep the contents of the style attribute (as was originally changed by the JS) upon going back in history, but did keep the CSS sheet declaration (which that part of course it was supposed to) that the element ends up at opacity 0 instead of 1. – Jimbo Jonny Dec 30 '12 at 17:46
  • @bobince - Your demo does work for me. But I have a theme in which this issue was found by multiple users, and I confirmed the its existence with my own tests. The state of the style attribute was not kept upon using the back button, confirmed by multiple non-affiliated people in different places on different machines. My explanation for it was as I outlined above, though your demo shows that my explanation of what was happening must be oversimplified. I'll look more into it and figure out why in the case of my theme the style attribute was not retained, then hopefully we'll have more info. – Jimbo Jonny Dec 30 '12 at 17:51
  • I had the same problem, the bfcache does not seem to work well when plug-ins are involved. After coming back to the page it complained about invalid JSAPI objects. Re-running the JS on the page is the only right thing to do in this case. – Fozi Jul 23 '13 at 15:03
  • @Fozi: Again: test case please. If you have genuinely found somewhere where the browser fails to recover the page JS/DOM state, then that is a bug and needs a repro case to be reported. Usually, the answer is simply that one of the scripts actively breaks something about the page, but it goes unnoticed as the page is not returned to without bfcache. – bobince Jul 23 '13 at 16:39
  • @bobince Sorry, no test case, but here is the scenario: Our plug-in allows access to credential hardware. There is a static `` tag and in `window.onload` access to the device is acquired. This access is exclusive so when the user leaves the page the access is revoked. Moreover according to the rules of NPAPI the plug-in internal objects for this page instance can be released at this point. When the user presses the back button the device object is in an invalid state. Hoping that this works for any NPAPI plug-in is relying on a memory leak. – Fozi Jul 23 '13 at 16:49
  • Oh! I didn't realise you meant native browser plugins. These are naturally outside the scope of JS/DOM so can't be recovered. It's still possible to make them work without breaking the bfcache by re-initialising them on the `pageshow`, but yeah, it is the one thing that doesn't naturally work. – bobince Jul 24 '13 at 09:16
  • Thanks a lot, i've been searching for a solution like `onpageshow` for quite some time now. Works like a charm! – michaeltintiuc Jan 25 '17 at 12:17
  • For me, the LastPass browser extension disabled the bfcache. My `body` `onload` handler was called when going back on my dev machines, so some widget was properly recreated - but for some co-workers it just wouldn't work, and the widget didn't update. A `window.onpageshow` handler to update the reloaded DOM should do the trick. Thanks! – ArchimedesMP Apr 27 '21 at 08:34
  • 1
    @Attacktive Now that archive link is rot :) Replace with web.dev link. – Heretic Monkey Aug 10 '22 at 21:24
29

You can check the persisted property of the pageshow event. It is set to false on initial page load. When page is loaded from cache it is set to true.

window.onpageshow = function(event) {
    if (event.persisted) {
        alert("From bfcache");
    }
};

For some reason jQuery does not have this property in the event. You can find it from original event though.

$(window).bind("pageshow", function(event) {
    if (event.originalEvent.persisted) {
        alert("From bfcache");
    }
});
Prince Agrawal
  • 3,619
  • 3
  • 26
  • 41
Mika Tuupola
  • 19,877
  • 5
  • 42
  • 49
  • Thanks for providing both javascript and jquery versions! You missed a close bracket at the end there (this isn't a moan!). I'll also note, for the sake of others, that IE and Chrome report .persisted is always false, regardless. – Magnus Smith Nov 05 '12 at 18:07
  • As noted by Magnus, this didn't work for me in Chrome until I removed the if statement. – Justin Aug 29 '14 at 17:45
  • This worked for me in Chrome 58.0.3029.110 (64-bit) and FF 53.0.2 (64-bit) without any changes. – kmoser May 27 '17 at 06:00
4

In my case window.onunload with an empty function didn't help (I tried to set a value for dropdown when user uses backwards button). And window.onload didn't work for other reason - it was overridden by <body onload="...">.

So I tried this using jQuery and it worked like a charm:

$(window).on('pageshow', function() { alert("I'm happy"); });
Shalguev
  • 81
  • 3
  • This tip helped me to prevent displaying a JQuery loading div (based on $(document).ready) while clicking the back button. I finally did it after hours of searching, thank you so much ! – Ben Dec 13 '22 at 14:28
1

Wire in an "onunload" event that does nothing:

<html><body>
<script type="text/javascript">
  window.onload = function() { alert('window.onload alert'); };
  window.onunload = function(){}; 
  alert('inline alert');
</script>
<a href="1.html">Click Me!</a>
</body></html>
Chris Haas
  • 53,986
  • 12
  • 141
  • 274
  • Not sure, I gave a up vote, looks like someone just downvoted every answer to this question... – Patonza Apr 14 '10 at 15:02
  • you should add to your answer that adding the onunload event to your page will actually disable the page being cached in its entirety. This does not simply make the JS run again, it will also make the server load go up a notch. This is really not a suggestion to take lightly, this should be carefully considered. – dreagan Feb 26 '15 at 10:53
  • @dreagan, this disables the bfcache but not necessarily the HTTP cache. The HTTP cache has a whole other set of rules. If you throw a server-side sleep in there you should notice it during the click back. Mozilla talks about this in their third question on the [FAQ for BFCache](https://developer.mozilla.org/en-US/docs/Working_with_BFCache). – Chris Haas Feb 26 '15 at 14:17
  • I was talking about the BFcache, should have specified that. That does not mean you should give out a suggestion like this without notifying the OP of the consequences. An alternative would be to use the onpopstate event to try and fire the javascript again. – dreagan Feb 27 '15 at 07:40
  • I still don't know if I understand. Why would "the server load go up a notch" if the client's local bfcache gets bypassed? Yes, the DOM will need to be rebuilt, but the HTML should be part of the client's HTTP cache. Yes, additional resources will need to be reloaded, but those should be part of the client's HTTP cache, too. As for the `onpopstate`, when this question was asked almost five years ago that event was still relatively new and [browser support was very inconsistent](http://stackoverflow.com/questions/3700440/html5-onpopstate-on-page-load#comment-30439949) – Chris Haas Feb 27 '15 at 14:42
1

As far as i know Firefox does not fire onLoad event on back.

It should trigger onFocus instead based from this link here.

systempuntoout
  • 71,966
  • 47
  • 171
  • 241
  • Tested it and windows.onfocus DOES indeed get called, even without setting the empty window.onunload handler. Setting onunload is a slightly nicer workaround but .onfocus should be fine too. Thanks :) – Patonza Apr 14 '10 at 15:21
1

A simple way to cause a page to execute JavaScript when the user navigates back to it using browser history is the OnPopState event. We use this to pause and replay the video on our home page (https://fynydd.com).

window.onpopstate = function() {

    // Do stuff here...
};
Michael A.
  • 49
  • 1
  • 3
  • OP is not asking about a single page app with a hash change, but literally navigating back to the first page with history.back. – kontur Dec 29 '21 at 12:16
-1

for some cases like ajax operations url change listener can be used

$(window).on('hashchange', function() {
        ....
});
Tamer
  • 91
  • 2
  • 10