Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to refresh client INLINE javascript

When using external js files, browsers can be forced to reload the files. See here.

Recently, I've found out that INLINE scripts are also cached, at least in Chrome, version 80.0.3987.132, example of snippet:

<html>
    <head>
        <script>alert("I am cached!");</script>
    </head>

    <body>
        <script>alert("Me too!");</script>
    </body>
</html>

What's the way of refreshing inline scripts?


Update 1: I do have to mention that the webserver returning the content is using HTTP 2.0

Update 2: A solution that works is to have an auxiliary script as base and when the page loads get the "real" script content through ajax or websocket then append it to head like so:

function addScript(content){
    let s = document.createElement('script');
    s.innerHTML = content;
    document.head.appendChild(s);
}

This does the job but its not optimal as it needs more requests than necessary.

Update 3: Headers sent from backend neither seem to work, using these headers:

Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") // HTTP 1.1.
Header().Set("Pragma", "no-cache") // HTTP 1.0.
Header().Set("Expires", "0") // Proxies.

Update 4: As per Jinxmcg's answer, the doc https://v8.dev/blog/code-caching-for-devs Don’t change URLs mentions:

we may one day decide to associate caches with the source text rather than source URL, and this advice will no longer be valid.

Probably that day has come and is also applied to inline scripts.


Thank you everyone for participating

Final Solution (works at least under my circumstances):

1 Backend headers:

w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate, max-age=0") // HTTP 1.1.
w.Header().Set("Pragma", "no-cache") // HTTP 1.0.
w.Header().Set("Expires", "0") // Proxies.

2 Random string in HTML, JS and CSS, example:

<html>
    <head>
        <style>
            --cache-color: #8528cc; //Random hex color generated by backend
        </style>
        <script>
            console.log("<?php echo date(); ?>");
            alert("I am cached!");
        </script>
    </head>

    <body>
        <div>Hidden DIV with a random value: <?php echo date(); ?></div>
        <script>
            console.log("<?php echo date(); ?>");
            alert("Me too!");
        </script>
    </body>
</html>
like image 741
Alpha2k Avatar asked Mar 15 '20 11:03

Alpha2k


People also ask

Does inline JavaScript get cached?

Chrome does try to cache inline scripts, by attaching their cache to the HTML document's resource, but these caches then become dependent on the entire HTML document not changing, and are not shared between pages.

How to reload browser in JavaScript?

You can use the location. reload() JavaScript method to reload the current URL. This method functions similarly to the browser's Refresh button. The reload() method is the main method responsible for page reloading.


3 Answers

I think the browser caches the inline javascript only when the page is opened for subsequent calls in that session and does not keep it after you close or refresh the page.

However, this means that the browser gets the HTML (including JS) from its cache in your case. Therefore you could try sending some headers along with your page that force the browser not to use it's cached HTML copy and use the new html+js.

In order to test if it is a HTML cache or "inline JS" cache issue, make your html dynamically change and confirm that it is changing on refresh but the inline JS execution does not.

You can find more details regarding js cache here: https://v8.dev/blog/code-caching-for-devs

like image 71
Jinxmcg Avatar answered Sep 22 '22 20:09

Jinxmcg


Using document.createElement('script') to "refresh" your scripts is bad solution. Probably something else is wrong with your caching.

Have you tried Cache-Control: "no-store, no-cache, must-revalidate, post-check=0, pre-check=0" ? https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control

If you are using proxies check out proxy-revalidate.

When debugging you could try shift + F5 or holding shift while pressing the reload button to force a complete refresh in Google Chrome. (if you have changed your script)

like image 41
Enrico Avatar answered Sep 20 '22 20:09

Enrico


Consider using the Cache-Control directive of max-age for your web page(s).

Normally, max-age might be set to a relatively long amount of time in seconds. This is done to improve performance by having the client frequently reuse cached files before they are refreshed.

Prior to releasing a change that you want the client to refresh immediately, drop the max-age value down to zero or a few seconds. Then, wait for the original max-age time duration to expire so that all active clients are updated with the new max-age value.

Once this wait period passes, push the file update(s) and revert to the original and longer max-age value.

This sequence will force the desired file change to be refreshed by the clients.

like image 24
JohnH Avatar answered Sep 18 '22 20:09

JohnH