views:

407

answers:

1

This behavior seems to only occur in the latest version of Safari (4.0.4). Using the example below, the page will create an alert box after 60 minutes. If you open the following page, click the link to Google, and hit your browser's back button, nothing will happen. That works as expected.

However, if I open the following page in Safari, click through the link, then hit the back button, the alert box will immediately appear. This seems to only happen on the first try and will not occur again until I do a hard refresh or completely close Safari.

Is this expected?

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">

<head>
    <script type="text/javascript">
        window.onload = function() {
                setTimeout(function() {
                    alert('hit');
                }, 60 * 60 * 1000);
        }
    </script>
</head>

<body>
    <a href="http://www.google.com"&gt;Click me, then press the browser's back button.</a>
</body>

</html>
+4  A: 

Good spot! Confirmed.

It's to do with the back/forward button cache. When you leave the page in Firefox or Safari (but not Chrome), it keeps the old page still loaded, just hidden. If you hit ‘back’ it can then re-show the page without having to re-parse it and re-run all the JavaScript, resulting in a much quicker navigation (especially useful for pages that start fetching stuff via AJAX onload).

In Firefox, the time a timeout will fire is preserved, so if you have five seconds to go before the timeout, leave the page, wait three seconds and come back, the timeout will fire in two more seconds. If the timeout would have fired whilst you were away from the page, it will fire immediately when you come back. Safari appears currently to fire every remaining timeout on return to the page, instead of just the ones that were scheduled to fire in the past. In my opinion this is a bug. Want to report it, or shall I?

You could work around it by having the timeout function check the real time via new Date().getTime() before taking its action. This is sometimes useful for some kinds of timeout anyway, as the callback time can drift backwards due to the browser being busy or the page being hidden from the bfcache. But due to this bug it can now move forwards too. Unfortunately, it seems Safari also doesn't implement the onpagehide function Firefox introduced to go with the bfcache, so you can't catch that.

Another option would be to browser-sniff for Safari and, when found, disable the bfcache by setting a window.onunload function — even one that does nothing. Firefox and Safari take this as a signal that the page wants to be really unloaded on leaving.

bobince
This error only seems to occur when running from a non-ssl site. I can reproduce the issue when visiting the page http : //localhost/test.html. However, the bug doesn't appear when I visit https : //localhost/test.html.
nivlam
Yes, I believe both Firefox and Safari disable the bfcache on HTTPS pages.
bobince