189

For all major browsers (except IE), the JavaScript onload event doesn’t fire when the page loads as a result of a back button operation — it only fires when the page is first loaded.

Can someone point me at some sample cross-browser code (Firefox, Opera, Safari, IE, …) that solves this problem? I’m familiar with Firefox’s pageshow event but unfortunately neither Opera nor Safari implement this.

Sebastian Simon
  • 14,320
  • 6
  • 42
  • 61
Bill
  • 4,055
  • 8
  • 26
  • 29
  • 6
    This is not a problem - it allows the web page to be quickly loaded when the user presses the Back button. See my answer below for details. The workarounds suggested here make the web page more annoying to the user, since navigating back/forward is slower. – Nickolay Feb 07 '10 at 22:59
  • 2
    @romkyns: your comment is not related to this question. When browsers don't restore the JS/DOM state, they do fire the load event. – Nickolay May 05 '12 at 23:29
  • iOS 5+ history back button solved here http://stackoverflow.com/a/12652160/1090395 – Mladen Janjetovic May 13 '15 at 09:20

15 Answers15

119

Guys, I found that JQuery has only one effect: the page is reloaded when the back button is pressed. This has nothing to do with "ready".

How does this work? Well, JQuery adds an onunload event listener.

// http://code.jquery.com/jquery-latest.js
jQuery(window).bind("unload", function() { // ...

By default, it does nothing. But somehow this seems to trigger a reload in Safari, Opera and Mozilla -- no matter what the event handler contains.

[edit(Nickolay): here's why it works that way: webkit.org, developer.mozilla.org. Please read those articles (or my summary in a separate answer below) and consider whether you really need to do this and make your page load slower for your users.]

Can't believe it? Try this:

<body onunload=""><!-- This does the trick -->
<script type="text/javascript">
    alert('first load / reload');
    window.onload = function(){alert('onload')};
</script>
<a href="http://stackoverflow.com">click me, then press the back button</a>
</body>

You will see similar results when using JQuery.

You may want to compare to this one without onunload

<body><!-- Will not reload on back button -->
<script type="text/javascript">
    alert('first load / reload');
    window.onload = function(){alert('onload')};
</script>
<a href="http://stackoverflow.com">click me, then press the back button</a>
</body>
Nickolay
  • 28,261
  • 8
  • 94
  • 160
user123444555621
  • 130,762
  • 25
  • 104
  • 122
  • @Pumbaa80, you're right -- I gave this a try in Firefox 3, and reproduced your results. Weird! – Jon Schneider May 20 '09 at 20:38
  • 1
    Very nice.. although this is an undocumented feature/bug though, and might simply stop working in future versions of the browser, but it's still interesting. – Wadih M. Sep 01 '09 at 01:52
  • 3
    This works as well (don't forget the onunload="" part, otherwise won't work on ff3): – Wadih M. Sep 01 '09 at 01:56
  • 3
    This is because the browser assumes the page is uncacheable if it has a `onunload` handler (the page has already destroyed everything; why cache it?). – Casey Chu May 10 '10 at 07:13
  • Two years later this is still going on. Got me puzzled for days. Pumbaa, thanks for this one! – patrick Nov 22 '10 at 15:16
  • 1
    apparently using onload breaks 'bfcache': http://friendfeed.com/paul/2b7ddce5/jquery-1-3-breaks-bfcache-because-it-binds – Alex Black Nov 22 '10 at 19:14
  • 14
    Answer seems not to work in modern browsers - checked in latest Chrome and Opera – Andrew Jun 17 '11 at 10:43
  • @Andrew: In Opera 11.11 everything seems to work just as before. Chrome 12 surprisingly fires onload even without the unload hack. Do you experience any different results? – user123444555621 Aug 02 '11 at 07:42
  • Pumbaa80 exactly what I'm seeing. – Benjamin Atkin Aug 10 '11 at 03:05
  • Sorry guys, I'm a bit confused, it's not clear what I need to do, simple add `onunload=""` to body tag? that's it? in all browsers? Tried that and it doesn't seem to work neither in Mozilla, nor in Chrome. – Burjua Aug 18 '11 at 16:58
  • @Buruja: Exactly. This answer is more than two years old, so it may not apply to certain newer browsers. However, I just tested in Firefox 6/Mac, and it still works here. – user123444555621 Aug 19 '11 at 06:42
  • This ended 10 hours of hating Android. – Blair Scott Aug 31 '11 at 18:48
  • 10
    it doesnt work in iPad safari... please, unmark this as an answer – xus Jun 08 '12 at 08:52
  • Still works fine for latest Safari pre Yosemite update – egr103 Oct 16 '14 at 11:51
  • Not working in Safari at least not for me in El Capitan nor iOS 10. – miho Sep 15 '16 at 14:54
76

Some modern browsers (Firefox, Safari, and Opera, but not Chrome) support the special "back/forward" cache (I'll call it bfcache, which is a term invented by Mozilla), involved when the user navigates Back. Unlike the regular (HTTP) cache, it captures the complete state of the page (including the state of JS, DOM). This allows it to re-load the page quicker and exactly as the user left it.

The load event is not supposed to fire when the page is loaded from this bfcache. For example, if you created your UI in the "load" handler, and the "load" event was fired once on the initial load, and the second time when the page was re-loaded from the bfcache, the page would end up with duplicate UI elements.

This is also why adding the "unload" handler stops the page from being stored in the bfcache (thus making it slower to navigate back to) -- the unload handler could perform clean-up tasks, which could leave the page in unworkable state.

For pages that need to know when they're being navigated away/back to, Firefox 1.5+ and the version of Safari with the fix for bug 28758 support special events called "pageshow" and "pagehide".

References:

Nickolay
  • 28,261
  • 8
  • 94
  • 160
  • That's very cool. I'm in a situation currently where my dom manipulations don't appear to be saved in the bfcache. Are there any situations where you might expect that? – Benson May 22 '10 at 01:06
  • 1
    @Benson: the possible reasons when Firefox will not save your page in bfcache are listed on the dev.m.o page I linked to. I don't think it's possible to have the page saved to bfcache, but certain DOM state not be saved. – Nickolay May 22 '10 at 19:28
  • Nickolay, I get your reluctance to force a reload and undo the good work done by the bfcache, but is there another way update the dom of the page in the bfcache? For example, consider the situation where I go from a page that has a list of messages to one of them, and when I go "back" I want the read/unread indicator to change. How can this be done without reloading the page? – Greg Aug 30 '10 at 19:11
  • @Greg: you mean as a developer controlling the page? Fire off an ajax request from a 'pageshow' listener. – Nickolay Sep 02 '10 at 19:56
  • Any ideas on how to use jQuery AND get fast bfcache support? – Alex Black Nov 22 '10 at 19:15
  • @Alex Black: as of Feb 2010, the answer was "use the newest jQuery". This was a problem in jQuery 1.3. – Nickolay Nov 24 '10 at 11:34
  • @Nickolay.Thanks for your explanation.My doubt is does pageShow(persisted property) event is fired in IE or chrome.If yes then please have a look at http://stackoverflow.com/questions/6363199/pageshow-event-in-javascript. – facebook Jun 15 '11 at 20:11
  • @Nickolay, **bfcache is totally buggy** if the website uses `pushstate` and `replacestate`. Do we have some proper solutions that actually work? – Pacerier Oct 12 '14 at 07:52
  • @Pacerier: I don't know, but you might get a better answer if you linked to questions / bug reports which led you to this conclusion. – Nickolay Oct 12 '14 at 12:31
  • Does *Chrome* have a bfcache? I've been able to trigger the bfcache with Safari and FF but not Chrome. And other threads/blogs suggest Chrome has not implemented a bfcache. See for example this Chrome issue: https://code.google.com/p/chromium/issues/detail?id=2879 – mla Jul 24 '15 at 06:29
  • mla, thanks for the link! I wrote this when Chrome was based on webkit and wrongly assumed it was automatically enabled in Chrome (it's supposed to be the fast browser, after all!) Updated the post. – Nickolay Jul 24 '15 at 11:00
31

I ran into a problem that my js was not executing when the user had clicked back or forward. I first set out to stop the browser from caching, but this didn't seem to be the problem. My javascript was set to execute after all of the libraries etc. were loaded. I checked these with the readyStateChange event.

After some testing I found out that the readyState of an element in a page where back has been clicked is not 'loaded' but 'complete'. Adding || element.readyState == 'complete' to my conditional statement solved my problems.

Just thought I'd share my findings, hopefully they will help someone else.

Edit for completeness

My code looked as follows:

script.onreadystatechange(function(){ 
   if(script.readyState == 'loaded' || script.readyState == 'complete') {
      // call code to execute here.
   } 
});

In the code sample above the script variable was a newly created script element which had been added to the DOM.

Brian Heese
  • 654
  • 5
  • 9
22

OK, here is a final solution based on ckramer's initial solution and palehorse's example that works in all of the browsers, including Opera. If you set history.navigationMode to 'compatible' then jQuery's ready function will fire on Back button operations in Opera as well as the other major browsers.

This page has more information.

Example:

history.navigationMode = 'compatible';
$(document).ready(function(){
  alert('test');
});

I tested this in Opera 9.5, IE7, FF3 and Safari and it works in all of them.

mplungjan
  • 134,906
  • 25
  • 152
  • 209
Bill
  • 4,055
  • 8
  • 26
  • 29
  • 2
    Obviously it's been a while (about 5.5 years) but it's worth noting that your link is dead. – Jeff May 07 '14 at 20:46
  • 2
    This solution does not work for me. I've got this issue in latest Firefox (45.0.1) – Armin Apr 01 '16 at 11:02
6

I couldn't get the above examples to work. I simply wanted to trigger a refresh of certain modified div areas when coming back to the page via the back button. The trick I used was to set a hidden input field (called a "dirty bit") to 1 as soon as the div areas changed from the original. The hidden input field actually retains its value when I click back, so onload I can check for this bit. If it's set, I refresh the page (or just refresh the divs). On the original load, however, the bit is not set, so I don't waste time loading the page twice.

<input type='hidden' id='dirty'>

<script>
$(document).ready(function() {
  if ($('#dirty').val()) {
    // ... reload the page or specific divs only
  }
  // when something modifies a div that needs to be refreshed, set dirty=1
  $('#dirty').val('1');
});
</script>

And it would trigger properly whenever I clicked the back button.

thorie
  • 152
  • 1
  • 6
  • 3
    Whilst this doesn't work in Firefox, I think it is a cunning way to handle the situation in IE/Chrome where the persistence of the hidden field is very useful. I've used your trick and also the "pageshow" event, so I cover all the main browsers. – Magnus Smith Nov 05 '12 at 18:18
  • What browser doesn't work with pageshow that this does? – Justin Aug 29 '14 at 18:12
4

I can confirm ckramer that jQuery's ready event works in IE and FireFox. Here's a sample:

<html>
<head>
    <title>Test Page</title>
    <script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script>
    <script type="text/javascript">
            $(document).ready(function () {
               var d = new Date();
               $('#test').html( "Hi at " + d.toString() );
            });
    </script>
</head>
<body>
    <div id="test"></div>
    <div>
        <a href="http://www.google.com">Go!</a>
    </div>
</body>
</html>
tothemario
  • 4,475
  • 2
  • 36
  • 34
palehorse
  • 22,870
  • 3
  • 36
  • 47
4

for the people who don't want to use the whole jquery library i extracted the implementation in separate code. It's only 0,4 KB big.

You can find the code, together with a german tutorial in this wiki: http://www.easy-coding.de/wiki/html-ajax-und-co/onload-event-cross-browser-kompatibler-domcontentloaded.html

j0k
  • 21,914
  • 28
  • 75
  • 84
Torben Brodt
  • 119
  • 4
  • 1
    Lone link is considered a poor answer (see [faq#deletion]) since it is meaningless by itself and **target resource is not guaranteed to be alive in the future**. [It would be preferable](http://meta.stackoverflow.com/q/8259) to include the essential parts of the answer here, and provide the link for reference. – j0k May 12 '14 at 12:55
4

I thought this would be for "onunload", not page load, since aren't we talking about firing an event when hitting "Back"? $document.ready() is for events desired on page load, no matter how you get to that page (i.e. redirect, opening the browser to the URL directly, etc.), not when clicking "Back", unless you're talking about what to fire on the previous page when it loads again. And I'm not sure the page isn't getting cached as I've found that Javascripts still are, even when $document.ready() is included in them. We've had to hit Ctrl+F5 when editing our scripts that have this event whenever we revise them and we want test the results in our pages.

$(window).unload(function(){ alert('do unload stuff here'); }); 

is what you'd want for an onunload event when hitting "Back" and unloading the current page, and would also fire when a user closes the browser window. This sounded more like what was desired, even if I'm outnumbered with the $document.ready() responses. Basically the difference is between an event firing on the current page while it's closing or on the one that loads when clicking "Back" as it's loading. Tested in IE 7 fine, can't speak for the other browsers as they aren't allowed where we are. But this might be another option.

Lightness Races in Orbit
  • 358,771
  • 68
  • 593
  • 989
Tom
  • 41
  • 1
4

If I remember rightly, then adding an unload() event means that page cannot be cached (in forward/backward cache) - because it's state changes/may change when user navigates away. So - it is not safe to restore the last-second state of the page when returning to it by navigating through history object.

3

jQuery's ready event was created for just this sort of issue. You may want to dig into the implementation to see what is going on under the covers.

ckramer
  • 9,285
  • 1
  • 21
  • 38
  • 6
    A long time later, `ready` does not seem to be triggered in Firefox, when using the Back button. See also [Nickolay's answer](http://stackoverflow.com/questions/158319/cross-browser-onload-event-and-the-back-button/2218733#2218733). – Arjan Jul 13 '10 at 13:57
2

Bill, I dare answer your question, however I am not 100% sure with my guesses. I think other then IE browsers when taking user to a page in history will not only load the page and its resources from cache but they will also restore the entire DOM (read session) state for it. IE doesn't do DOM restoration (or at lease did not do) and thus the onload event looks to be necessary for proper page re-initialization there.

Sergey Ilinsky
  • 29,849
  • 9
  • 51
  • 56
2

I tried the solution from Bill using $(document).ready... but at first it did not work. I discovered that if the script is placed after the html section, it will not work. If it is the head section it will work but only in IE. The script does not work in Firefox.

Johann
  • 29
  • 2
1

OK, I tried this and it works in Firefox 3, Safari 3.1.1, and IE7 but not in Opera 9.52.
If you use the example shown below (based on palehorse's example), you get an alert box pop-up when the page first loads. But if you then go to another URL, and then hit the Back button to go back to this page, you don't get an alert box pop-up in Opera (but you do in the other browsers).

Anyway, I think this is close enough for now. Thanks everyone!

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>
<meta http-equiv="expires" content="0">
<script src="jquery.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready( 
                    function(){
                      alert('test');
                    }
                 );
</script>
</head>
<body>
<h1>Test of the page load event and the Back button using jQuery</h1>
</body>
</html>
Bill
  • 4,055
  • 8
  • 26
  • 29
1

Unload event is not working fine on IE 9. I tried it with load event (onload()), it is working fine on IE 9 and FF5.

Example:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
    jQuery(window).bind("load", function() {
        $("[name=customerName]").val('');
    });
</script>
</head>
<body>
    <h1>body.jsp</h1>
    <form action="success.jsp">
        <div id="myDiv">

        Your Full Name: <input name="yourName" id="fullName"
            value="Your Full Name" /><br> <br> <input type="submit"><br>

        </div>

    </form>
</body>
</html>
Andro Selva
  • 51,960
  • 51
  • 189
  • 237
mallesham
  • 11
  • 1
0

I have used an html template. In this template's custom.js file, there was a function like this:

    jQuery(document).ready(function($) {

       $(window).on('load', function() {
          //...
       });

    });

But this function was not working when I go to back after go to other page.

So, I tried this and it has worked:

    jQuery(document).ready(function($) {
       //...
    });

   //Window Load Start
   window.addEventListener('load', function() {
       jQuery(document).ready(function($) {
          //...
       });
   });

Now, I have 2 "ready" function but it doesn't give any error and the page is working very well.

Nevertheless, I have to declare that it has tested on Windows 10 - Opera v53 and Edge v42 but no other browsers. Keep in mind this...

Note: jquery version was 3.3.1 and migrate version was 3.0.0

bafsar
  • 834
  • 1
  • 12
  • 14