2

I need to reload the page in Javascript. I use window.location.reload for that purpose. Now, I observe a strange behaviour in Chrome: Chrome always connects to the server and asks if the document was modified. Though a 304 Not Modified is returned, there is still a roundtrip to the server that I want to avoid.

I've also tried explicitly using window.location.reload(false) to tell chrome to use the cache, but without success. Not that I have an active hash (#) fragment in the url that I reload.

The response headers of the resource are as following:

HTTP/1.1 304 Not Modified
Server: nginx/1.2.2
Date: Sat, 01 Jun 2013 13:19:56 GMT
Last-Modified: Sat, 01 Jun 2013 13:04:55 GMT
Connection: keep-alive
Expires: Sun, 02 Jun 2013 13:19:56 GMT
Cache-Control: max-age=86400
Access-Control-Allow-Origin: *

So, the Cache-Control and the Expires header are both set and should tell chrome not to update the resource within 24hours.

I do not reload the page using F5/CMD+R, but instead I click on a link, that will have a javascript event that will change window.location.hash and then call window.location.reload(false). But Chrome keeps setting the Cache-Control: max-age=0 header for the request - which I don't want. Chrome should use it's internal cache and not send anything to the server at all.

There is no problem with the same code using Firefox, FF uses the cached version without connection to the server at all.

How can I fix this?

EDIT: Here is a simple example that you can use to tryout yourself: http://webspace.markdown.io/reloadtest.html

EDIT: I have developer tools closed and verify the headers via tcpdump -s 1024 -l -A dst port 80 on the server. I have also unticked "disable browser cache" in the developer tools.

EDIT 2: Note that if close the tab and enter the Url into a new one, Chrome correctly uses the cache. Only clicking a link (which will result in a window.location.reload is affected.

Dynalon
  • 6,577
  • 10
  • 54
  • 84
  • I did that already, have updated the question. – Dynalon Jun 01 '13 at 13:38
  • Cool, one more thing, have you tried this: http://stackoverflow.com/a/4844816/1348195 – Benjamin Gruenbaum Jun 01 '13 at 13:40
  • I've modified the nginx.conf not to output an `Expires` header, but only to attach `Cache-control: max-age=86400`. Still the same result. – Dynalon Jun 01 '13 at 13:46
  • Why do you need to refresh the page? – Jordan Jun 11 '13 at 16:14
  • @Jordan it does not matter to this question why I need to do this. All you can do, is tell my I got the wrong problem, which will not help with the original question in place here. I know there are other ways of doing what I want to do, and I will ask (new) questions on them if appropriate. But this question (=thread) won't benefit from workarounds. – Dynalon Jun 13 '13 at 13:20

4 Answers4

3

Answering myself, after some more research:

It simply can't be done.

The problem is not related to the hash value at all, and arises even if you don't use a hash.

It seems window.location.reload() can not be used to control whether or not the current resource (indicated by window.location.href) is to be used from cache or not. Although the documentation on MDN suggests otherwise. The official W3C specs on the Location object in the window object are also not much of help.

Chrome and Firefox will always perform a round-trip to the server, asking for the current resource, no matter what parameter you pass to .reload(). The parameter was originally introduced to force POST requests be repeated as GETrequests - this has nothing to do with caching. (Carefull when using Firebug: I first thought FF does not send a request because it is not shown in Firebug - but when you look at the webserver logs, you can see that it actually does).

I can observe that the presence of the boolean parameter influences whether or not the browser will append a Cache-Control: max-age=0 header to the request. But this only reduces the data that is transfered, and will not eliminate the server connection at all. A roundtrip is done in any case.

Dynalon
  • 6,577
  • 10
  • 54
  • 84
1

In the latest HTML5 draft (which is likely to become the final HTML5 standard without modification) the location.reload() function does not take any boolean parameter anymore. One should thus not rely on the parameter in any way when targeting HTML5.

Dynalon
  • 6,577
  • 10
  • 54
  • 84
0

You could do something like that:

function reload_page() {
    window.location.hash = new Date().getTime();
    window.location.replace(window.location.href);
    loaded();
}
window.onload = loaded;

function loaded() {
    document.getElementById('thetime').innerHTML = new Date().toISOString();
}
A. Wolff
  • 74,033
  • 9
  • 94
  • 155
  • window.location.replace is a bad Idea as it will destroy the pushState of the app. I am using a javascript framework that passes view data in the hash, so a broken pushState will result in total breakage of the page if the users hits his back button. – Dynalon Jun 11 '13 at 10:40
0

Reloading the page, with either F5 or window.location.reload, makes a network connection even if navigating to the page from a different page would look directly in the cache. While reload(true) forces it to bypass the cache (getting 200 from the server instead of 304), reload(false) does not force it to look at the cache before deciding if it needs to connect to the server.

If the browser won't look in the cache to reload a page and it won't reload the page when a link is followed that only differs by the fragment, try fooling it into thinking it's loading a different page to get it to look in the cache. This uses ajax to get (from the cache) the page you're already looking at and with it replace the entire document. Then it replaces the URI fragment with a new one -- changing the fragment this way triggers whatever function in the JavaScript framework listens for changes in the fragment.

<html>
<head>
    <script src="http://code.jquery.com/jquery-1.8.1.min.js"></script>
</head>
<body>
    <p>
        It is: <span id="thetime"></span>
    </p>
    <a href="javascript: reload_page()">Reload</a>
    <script type="text/javascript">
        function reload_page() {
            var hash = new Date().getTime()
            $.get(window.location, function(data) {
                var newDoc = document.open("text/html", "replace");
                newDoc.write(data);
                newDoc.close();
                window.location.hash = new Date().getTime();
            });
        }
        document.getElementById('thetime').innerHTML = new Date().toISOString();
    </script>
</body>
</html>
Jordan
  • 4,510
  • 7
  • 34
  • 42
  • Problem is, the hash actually carries important view data for a javascript framework, and should not be cluttered. And you maybe got my question wrong, I don't want to bypass the cache, I want to force the browser to USE the entries in the cache and NOT do a real network connection. – Dynalon Jun 11 '13 at 10:38
  • @Dyna You misunderstood; I updated the answer to clarify. What do you mean by cluttering the fragment? – Jordan Jun 11 '13 at 15:44
  • The first section of your (updated) answer makes sense and seems to be true, from what I can observe in Chrome. However, I think this is stupid or falsely implemented in Chrome. The `true` of `false` parameter in `window.location.reload` just seems to indicate whether or not a `Cache-Control: max-age=0` is added to the __request__. The parameter should however in my opinion indicate whether an object from the browser cache that is _fresh_ in terms of the cache policy (i.e. due to a valid expires header) is considered. If set to `true`, even _fresh_ objects should be considered _stale_. – Dynalon Jun 11 '13 at 19:52
  • I will have to dig into the ECMA standards for clarification. I think the correct answer to my question is: "It can't be done. There is no way to trigger a page-reload in Javascript that will not connect to the remote server, even if all required objects are still _fresh_ and _valid_ copies in the browser cache." – Dynalon Jun 11 '13 at 19:54
  • The [official DOM standard](http://www.w3.org/TR/Window/#location) is not specific on `window.location.reload`. The MDN states: "reload(forceGet): Reload the document from the current URL. forceget is a boolean, which, when it is true, causes the page to always be reloaded from the server. If it is false or not specified, the browser may reload the page from its cache.". Thats how it is implemented in FF, but not Chrome: If `forceGet` is false, a cached version of _current_ location is used - no server connection is performed in FF. I will open a chrome bug report to adress this. – Dynalon Jun 11 '13 at 20:07