skip to Main Content

I have a piece of code with an API call in the topmost JS import which I need to use everywhere else in the project.
How to make this asynchronous?

My HTML file looks like:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="src/style.css">
  </head>
  <body>
    <h1 id="header"></h1>

    <script src="src/script1.js"></script>
    <script src="src/script2.js"></script>
  </body>
</html>

First JS file:

const fetchData= async () => {
    const configUrl = 'https://jsonplaceholder.typicode.com/todos/1';

    try {
        const response = await fetch(configUrl);

        if (!response.ok) {
            throw new Error(`Network response was not ok: ${response.status} - ${response.statusText}`);
        }

        const res = await response.json();
        console.log('data 0:',res)
        return data;
    } catch (error) {
        console.error('Error fetching data:', error);
    }
};

window.data = fetchData();

console.log("data 1:",data);

Second JS file:

console.log("data 2:",window.data)

Basically I want window.data with the data from the endpoint to be accessible everywhere. I want to continue the program execution only after the api call is done. That is, the thread should be blocked for the API call and rest of the program (js files) should execute only after the api call.
Im not ready to move other JS file code to first 1 nor import it inside first using @import in .then block of first.

Is there any clean approach for this?

Live example: https://playcode.io/1696111

In the example I want console.log inside script2.js to print the API data.

3

Answers


  1. You can’t* block the main thread, but you can defer loading other scripts until the data is received:

    function loadScript(url) {
       // for example,
       let script = document.createElement('script');
       script.type = 'text/javascript';
       script.src = url;
       document.body.appendChild(script)
    }
    
    fetchData().then(_ => loadScript(script2))
    

    * By saying "can’t" I mean "while you technically might be able to, browser vendors put a lot of effort into preventing you from doing so and it would be unwise to go against them".

    Login or Signup to reply.
  2. Vue SFC Playground

    Just add type="module" to your scripts
    and use console.log("data 2:", await window.data)

    Login or Signup to reply.
  3. Have you considered using an await import("...") to load an index of all the dependent modules?

    The script1 would be

    // src/script1.js
    
    const fetchData= async () => {
        const configUrl = 'https://jsonplaceholder.typicode.com/todos/1';
    
        try {
            // ...
            return data;
        } catch (error) {
            console.error('Error fetching data:', error);
        }
    };
    
    (async (index) => {
        window.data = await fetchData();
        console.log("data 1:",data);
        try {
            // import the index file after the data arrives
            await import(index)
        } catch (e){
            console.log("error importing", e)
        }
    })("./index.js")
    

    Then you could make a js index module like the following

    // src/index.js
    
    export * from "./script2.js"
    // more import/export ...
    

    And in the index.html you have to remove all the script other than the script1.js.

    Unfortunately the await import(index) doesn’t work on https://playcode.io/1696111 so you have to find another way around to play with this, like python3 -m http.server in your local folder, then opening the console of the browser you should see

    data 0: {userId: 1, id: 1, title: 'delectus aut autem', completed: false}
    data 1: {userId: 1, id: 1, title: 'delectus aut autem', completed: false}
    data 2: {userId: 1, id: 1, title: 'delectus aut autem', completed: false}
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search