Loading scripts dynamically with async/await in JavaScript

I may be committing a typical beginner error.

Aim

I have a script named loader.js, where I intend to provide a collection of JavaScript files that control the shape, size, and position of components.

The structure of the file is as follows:

const loadScript = (FILE_URL, async = true, type = "text/javascript") => {
    return new Promise((resolve, reject) => {
        try {
            const scriptEle = document.createElement("script");
            scriptEle.type = type;
            scriptEle.async = async;

            //scriptEle.async = false; // i tried with this line as well.
            scriptEle.defer = true;

            scriptEle.src = FILE_URL;

            scriptEle.addEventListener("load", (ev) => {
                resolve({ status: true });
            });

            scriptEle.addEventListener("error", (ev) => {
                reject({
                    status: false,
                    message: `Failed to load the script ${FILE_URL}`
                });
            });

            document.body.appendChild(scriptEle);
        } catch (error) {
            reject(error);
        }
    });
};





$(document).ready(function () {

    setTimeout(proceed, 1);               // wait for the document to be fully ready.


});



async function proceed() {

    await loadVars();              // Load variable definitions
    await loadComponents();        // load component definitions 
    await make_components();       // and populate them

}


function make_components() {

    switch (monitorType) {         // monitor type should be defined once loadvar executes (and console.log agrees) 

        case 1 :

            addMobileHeader(wfull, hfull * 0.1);
            addMobileHeroBlock(wfull, hfull* 0.7);
            break;

    }

}



function loadVars() {

    loadScript("variables.js").then( data  => {
        console.log("Variables: Script loaded successfully", data);
    })
    .catch( err => {
        console.error(err);
    });

}


function loadComponents() {

    loadScript("components_mobile.js").then( data  => {
        console.log("Components (mobilephone): Script loaded successfully _ mobile", data);
    })
    .catch( err => {
        console.error(err);
    });



    loadScript("components_wide.js").then( data  => {
        console.log("Components (widescreen):Script loaded successfully _ wide", data);

    })
    .catch( err => {
        console.error(err);
    });


}

Issue

Naturally, make_components() gets triggered before loadVars finishes its execution.

Attempt at Solution

Following guidance from this response, my assumption was that since variables.js is added first, it will run prior to the next (deferred) file, components_mobile.js, being loaded and executed.

Only after all processes are completed, including loading and executing variables.js and components_mobile.js, will the make_components function execute, finding all the definitions in the loadVars file.

I understand that I could directly call the subsequent function within the .then section like so:

loadScript("variables.js").then( data  => {
            console.log("Variables: Script loaded successfully", data);
          //call next function here
        })

However, this approach will result in a complex chain of functions that would be difficult for me to debug.

Question

Is there a method to compel the JS engine in Chrome/Firefox to pause until one script is entirely loaded and executed? Thank you.

EDIT: Without incorporating third-party libraries, if feasible please.

Answer №1

Your functions loadVars and loadComponents are not returning any values, which means that await loadVars() and await loadComponents() do not effectively wait for anything to complete. To fix this, you need to return a promise.

If you prefer using the .then syntax, modify your code as follows:

function loadVars() {
  // add "return" on the next line
  return loadScript("variables.js")
    .then(data => {
      console.log("Variables: Script loaded successfully", data);
    })
    .catch( err => {
      console.error(err);
    });
}

If you prefer utilizing async/await, adjust your code like this:

async function loadVars() {
  try {
    const data = await loadScript("variables.js");
    console.log("Variables: Script loaded successfully", data);
  } catch (err) {
    console.error(err);
  }
}

Please make similar adjustments in the loadComponents function as well.

Answer №2

Appreciations to @Nicholas Tower for the insight on using the return promise.

Upon consulting chatGPT, a solution closely resembling Nicholas Tower's was provided.

Begin by defining the loader function:

/* Solution by ChatGPT */
function loadScript(url) {
  return new Promise((resolve, reject) => {
    const script = document.createElement("script");
    script.src = url;
    script.async = true;
    script.addEventListener("load", () => {
      // Script has been loaded and executed
      resolve();
    });
    script.addEventListener("error", () => {
      // Script failed to load
      reject(new Error(`Failed to load script: ${url}`));
    });
    document.body.appendChild(script);
  });
}

Next, Invoke the loader function:

/* Ensure document is ready before proceeding*/
$(document).ready(function () {
    setTimeout(proceed, 1);                                     // Fire the proceed event after one second of body being ready.
});

async function proceed() {

    await loadVars();                                           // Wait for loadvars to complete
    await loadComponents();
    make_components();                                          // This call does not require awaiting as everything should be ready now.

}

async function loadVars() {

    await loadScript ("variables.js");                          // Load variable definitions

}

async function loadComponents() {

    await loadScript ("components_mobile.js");
    await loadScript ("components_wide.js");

}

It's important to note that each call to loadScript is enclosed in another function. To achieve this multiple-wrapping process, chatGPT advises making each wrapping layer an async function and utilizing awaits for each wrapped function.

Then:

async function make_components() {

switch (monitorType) {

    case 1 :

        addMobileHeader(wfull, hfull * 0.1);
        addMobileHeroBlock(wfull, hfull* 0.7);
        break;

}

}

Results indicate smooth functionality.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Xap or js Silverlight media player

Currently developing a Silverlight video player, I stumbled upon the JW Player for inspiration. I know that Silverlight apps are typically contained within .xap files, but JW Player utilizes JavaScript scripts to implement Silverlight logic. Can you plea ...

Optimal method for linking jQuery ajax requests to transfer data

Handling several asynchronous ajax calls in a specific order with information passing between them can be quite challenging. The current approach, even with just three API calls, can be cumbersome. Trying to manage five API calls makes it nearly impossible ...

What is the best way to eliminate products that have already been utilized?

Take a look at my code snippet. $(function() { $("#tags input").on({ focusout: function() { var txt = this.value.replace(/[^a-z0-9\+\-\.\#]/ig, ''); // only allow certain characters if (txt) $("<span/& ...

What's the best way to include various type dependencies in a TypeScript project?

Is there a more efficient way to add types for all dependencies in my project without having to do it manually for each one? Perhaps there is a tool or binary I can use to install all types at once based on the dependencies listed in package.json file. I ...

The Chrome browser does not recognize Sys.WebForms

I am encountering an issue with my Web-Application when trying to perform partial updates. The error message "Sys.WebForms is undefined in Chrome (latest version)" keeps popping up. Despite my extensive research efforts, I have not been able to find a solu ...

Can you locate the hiding spot of the express-session cookie?

After setting a very short cookie max-age (10 secs) in my express-session, I confirmed that it is working as expected: app.use(session({ secret: 'xxx', resave: false, saveUninitialized: true, cookie: { secure: true, maxAge: 10000 } })); ...

What is the best way to modify the appearance of the button?

I'm attempting to change the appearance of buttons at the top of a webpage to be square and blue. I have jQuery code for this purpose, but it doesn't seem to be functioning correctly. Here is the snippet of code I am using: $(document).ready(fu ...

Iterating through a collection of objects, triggering a promise for each object and recording its completion

I have encountered a challenge where I need to iterate through an array of objects obtained from a promise, and for each object in the array, I must invoke another promise. After all these promises are executed, I want to display "DONE" on the console. Is ...

Working on rectifying the Chat Engine API code that was causing a 403 Status Code to be generated

Encountering a status code 403 while attempting to create a chat engine IO page, even though all authentication headers are believed to be accurate. Double-checked for typos but still unable to identify the issue. Despite console logging the user correctly ...

Trigger a function in jQuery when the DOM undergoes changes

Up until now, I have been utilizing livequery which has served its purpose. However, it tends to slow down the page browsing experience, so I am in search of an alternative solution. I have a function that performs ajax on elements with a specific class l ...

Understanding the Significance of this Regular Expression

I need assistance with regular expressions as I am not very familiar with them. The issue I am facing is related to a jQuery dynacloud plugin that stops working when a regex match occurs in my code. Can someone please help me understand what this regex mat ...

Exploring the interactive doughnut graph using SVG and Vue.js

Looking to create a unique dynamic donut chart using SVG and Vue. I want it to mirror the exact SVG format found on this webpage: (To see the animated chart, select a dish and click on ingredients) This might not have been the best approach, but it was ...

This TypeScript error occurs when the props are not compatible and cannot be assigned to

Hello fellow Internet dwellers! I am a novice in the world of coding and TypeScript, seeking some assistance here. I am attempting to extract an array of objects from props, transform it into a new object with specific information, and then return it - ho ...

Passing a selected option in a select box to another website is achievable using JavaScript

I'm still learning JavaScript and I would like to have a user be directed to another page when they select an option from a dropdown menu. Any suggestions on how to accomplish this? ...

Attempting to confirm the validity of my form

I have been attempting to validate my form in JSP, but unfortunately it is not working as expected. The form runs fine, however, the function 'validatemark' from my JavaScript file is not being called. Below is a snippet of my code: <%@ ...

Retrieve information from an ajax call within an Angular application

I need assistance with 2 requests I have. $.ajax({ type: "POST", url: "http://sandbox.gasvisor.com:9988/uaa/oauth/token", data: "grant_type=client_credentials", headers: { 'Content-Type': 'application/x-www-form-urlencoded&a ...

Nextjs throws an error indicating that the element type is invalid when an object is passed into the export function

Currently, I am in the process of developing a blog page and facing an issue while attempting to pass generic data stored in an object inside an array. The specific error message I am encountering is "Error: Element type is invalid: expected a string (for ...

The componentWillUnmount method is not being called

I'm currently working on a Backbone application and I'm in the process of integrating React components. The React component is being mounted using the following code: ReactDOM.render( <WrappedComponent />, node ); where "node" represents ...

Target only the <a> elements within a specific <div> using JavaScript

How can I target the first occurrence of the letter 'a' in this code using JavaScript? (href=some.php) <div class="accordionButton"><div id="acr_btn_title"><a href="some.php"><p>stuff</p></a></div><di ...

A guide on implementing nested child routes in AngularJS 2

I have successfully completed routing for two children, but now I want to display nested routes for those children. For example: home child1 child2 | grand child | grand child(1) ...