Using fetch to get page settings

Viewed 92

I am very hesitant to ask this question. There are many many answers out there around my question, but they don't deal with the <script> tag and normal HTML and javascript. So here it goes...

Here is a minimal reproduction of my scenario. (My real scenario involves minified third-party scripts that are way beyond my skill or comprehension, yet require configuration.)

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Test App</title>
    </head>
    <body>
        <script src="setup-configuration.js"></script>
        <script src="do-something.js"></script>
        <p>Test Text</p>
    </body>
</html>

setup-configuration.js

config = 'Not Set Yet';

fetch('config.json')
  .then(response => response.json())
  .then(json => config = json)
  .catch( error => console.error('error:', error) );

do-something.js

console.log(config)

config.json

{
    "SomeSetting": "SomeValue"
}

The issue here is that the call to console.log(config) uses the config variable before it is setup. This is (of course) because the fetch call uses a promise and is asynchronous. Normally, I would just put the dependent code as part of the promise chain. But I basically need all of my application to wait on this script to get the configuration code. (The do-somthing.js script is really several very complicated 3rd party scripts that I would have no chance of modifying to work in one file.)

I originally used a synchronous XMLHttpRequest call, but I chrome debug tools were warning that I was doing it wrong and that it will be removed from future versions of javascript.

Hence I am wondering how values from one <script> tag can be used in another <script> tag when retrieved via fetch. Is there a way to chain promises between <script> tags?

2 Answers

I have been doing exactly this kind of thing for a while (because of how I structured my website).

The way to go is to have only 1 script tag. This swill be responsible for chaining scripts and other code that have dependencies

Make your config script look something like this:

let head = document.getElementsByTagName('head')[0];
function script(src) {
    return new Promise(res=> {
        let e = document.createElement('script');
        e.src = src;
        e.onload = res;
        head.appendChild(e);
   });
} 
let config;
fetch('config.json').then(r=>r.json()).then(j=>config=j).then(()=> {
    script('s1.js'); script('s2.js');
}) ;

The website is https://www.sharember.com

Just make config a promise, and await it in the other file:

setup-configuration.js

configPromise = new Promise((resolve, reject) => {
    fetch('config.json')
        .then(response => response.json())
        .then(json => resolve(json))
        .catch(error => {
            console.error('error:', error);
            reject(error);
        });
});

do-something.js

(async function() {
     const config = await configPromise;
     console.log(config);
})();

Technically you could even just do:

configPromise = fetch('config.json')
    .then(response => response.json());

for the setup, since it returns a promise anyways

Related