5

In an web pure vanilla JavaScript app that does not use service workers, I would like to explicitly cache a JavaScript file that is sitting on an AWS S3 file server. The following script would be sitting in the index.html file for the application (I’ve modified the URL as it's a client project):

<script>
    caches.match('https://s3.amazonaws.com/com.myproject/myjavascript.js')
    .then(function(response) {
        if (response) {
            return response;
        } else {
            fetch('https://s3.amazonaws.com/com.myproject/myjavascript.js')
            .then(function(res) {
                return caches.open('mycache')
                .then(function(cache) {
cache.put('https://s3.amazonaws.com/com.myproject/myjavascript.js',res.clone());
                   console.log(res.clone());
                   return res;
                });
            });
       }
    });
</script>

I believe this code should do the following: Check if the myjavascript.js file is in the cache. If it is, return the JavaScript file which would then be executed by the browser. If myjavascriptfile.js is not found in the cache, it will be fetched and placed in the subcache ‘mycache’ and finally returned to the browser where it would be executed.

After running this, I find the URL for the file in the cache with a response of “Ok”, but the code is not executed by the browser and I don’t see the file contents in sources within the Chrome browser developer tools.

Why would this not be working? What is wrong with my thinking on this.

Many thanks, Fred

Fred
  • 51
  • 1
  • 3
  • What are you getting in your console logs? – Hunter Oct 15 '17 at 19:02
  • Are you sure this can't be done using declarations in htaccess, http headers, etc.? Also, are these javascript commands compatible with all current browsers? Also, there might be a js library that handles this. – eyal_katz Oct 15 '17 at 22:10
  • 1
    Thanks for your comment Eyal. Fetch has pretty good browser support (79% globally at the moment: http://www.caniuse.com/#search=fetch). It's a technical requirement that I used Vanilla JavaScript for this and yes JQuery can handle this. – Fred Oct 16 '17 at 20:57

1 Answers1

2

fetch by itself will not execute JavaScript. It simply makes a request for the specified content and make it available for the code to access. If you really want to continue with this approach it is possible to take the text and eval it.

const url = 'https://unpkg.com/underscore@1.8.3/underscore-min.js';
caches.match(url)
  .then(function(response) {
    if (response) {
      return response;
    } else {
      return fetch(url)
        .then(function(res) {
          return caches.open('mycache')
            .then(function(cache) {
              cache.put(url,res.clone());
                console.log(res.clone());
                return res;
            });
        });
    }
  })
  .then(function(response) {
    console.log(response);
    response.text().then(function(text) {
      eval(text);
      console.log(_);
    });
  });

Note: Why is using the JavaScript eval function a bad idea?

The code sample you have is a pattern commonly found in Service Workers. The reason it works in that context is the initial request is from <script> tags and not direction invocation of fetch. Because of the <script> tag the browser handles automatically executing the returned content.

<script src="https://unpkg.com/underscore@1.8.3/underscore-min.js"></script>
abraham
  • 46,583
  • 10
  • 100
  • 152
  • 1
    Thanks Abraham for your excellent and clear explanation. However, when it executes the first time and it tries to access response.text() in the final then clause I get the error message "Cannot read property 'text' of undefined" . The 2nd time I run it, it does pull the script from the cache and I'm able to do a console log to see that code, but the code it is not executing. The script runs successfully when I simply put – Fred Oct 16 '17 at 20:52
  • To fix the error on first run the fetch has to be returned `return fetch(url)` – abraham Oct 16 '17 at 21:39
  • The `fetch` is not an action that will delay a `window.load` event. That event is triggering before you are fetching and evaling the script. – abraham Oct 16 '17 at 21:40
  • 1
    Thanks @abraham. Since fetch does not on it's own invoke the code execution and since the `window.load` event has already occurred by the time the script is fetched and evaluated, by what mechanism could you get the code to run automatically when this page is loaded? – Fred Oct 16 '17 at 23:46
  • The best approach would be to use a standard ` – abraham Oct 17 '17 at 01:02
  • In my scenario a service worker is not an option as it has to support browsers that do not support service workers. My objective was to be able to inject a few lines of vanilla JavaScript into any web page and have it retrieve my script, from a CDN that I've set up, and automatically execute it where the script has my application logic. The hope was that once the script was initially retrieved I could then store the script in cache and run it from the cache the next time the page was called, without reaching out to the CDN again. I take it that this isn't possible without a service worker? – Fred Oct 17 '17 at 03:15
  • `caches` is supported by the same browsers that support Service Workers so you won't be able to support any additional browsers by using it in the main thread. Service Workers is they way to support offline web apps. Edge and Safari are both working on support so soon all major browsers will support it. – abraham Oct 17 '17 at 14:43