skip to Main Content

I am probably making a rookie mistake.

Goal

I have a script loader.js, where I want to supply a set of javascript files intended to manage component shape, size, position, etc.

The file is like this:

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);
    });


}

Problem

Of course, make_components() is triggered before loadVars completes execution.

Attempt to solution

Inspired from this answer,I thought that since variables.js is added first, it will be executed first, before the next (deferred) file, components_mobile.js is loaded and executed.

And only after all that is done, then the make_components function will execute, and will find all the definitions in loadVars file.

I know that I can make a call the next function directly in the .then part, like

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

But that will create a hell of chained function very hard for me to debug.

Question

Is there a way i can force the JS engine in chrome/ firefox to wait while one script is fully loaded and executed? Thank you.

EDIT : Without third party libraries, if possible please.

3

Answers


  1. Chosen as BEST ANSWER

    Thanks to @Nicholas Tower. Indeed, the return promise is a good idea.

    I asked chatGPT, and chatGPT gave this solution which is very close to Nicholas Tower.

    Define the loader function:

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

    Then Invoke the loader function :

    /* wait for document to be ready*/
    $(document).ready(function () {
        setTimeout(proceed, 1);                                     // After one second, after body is ready, fire the proceed event.
    });
    
    
    
    
    async function proceed() {
    
        await loadVars();                                           // await FOR loadvars to complete
        await loadComponents();
        make_components();                                          // not an await call. by now everything is ready.
    
    }
    
    async function loadVars() {
    
        await loadScript ("variables.js");                          // Load variable definitions
    
    }
    
    async function loadComponents() {
    
        await loadScript ("components_mobile.js");
        await loadScript ("components_wide.js");
    
    }
    

    note, that each call to loadScript itself is wrapped in another function. In order to achieve that multiple-wrapping, chatGPT says, that you need to make each layer of wrap an async function, and each wrapped function an await.

    Then :

    async function make_components() {

    switch (monitorType) {
    
        case 1 :
    
            addMobileHeader(wfull, hfull * 0.1);
            addMobileHeroBlock(wfull, hfull* 0.7);
            break;
    
    }
    

    }

    This works fine.


  2. Try to do this:

    async function proceed() {
    
       await loadVars();              // Load variable definitions
       await loadComponents();        // load component definitions 
       await make_components();       // and populate them
    
    }
    
    
    async 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;
    
        }
    
    }
    
    
    
     async function loadVars() {
    
           loadScript("variables.js").then( data  => {
           console.log("Variables: Script loaded successfully", data);
        })
       .catch( err => {
         console.error(err);
       });
    
    }
    
    
    async 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);
    });
    
    
    }
    
    Login or Signup to reply.
  3. Your loadVars and loadComponents are implicitly returning undefined, so await loadVars() and await loadComponents() don’t actually wait for anything. You’ll need to return a promise.

    If you prefer .then syntax, do:

    function loadVars() {
      // added "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 async/await, do:

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

    And make a similar change in loadComponents

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search