0

I am adding a plugins system to a program and I want the user to be able to include files and raw information. I have a problem, however with loading the scripts. I want to wait for all the scripts to load (I don't know the number of them, however). An example is this:

Plugins.json:

{"include":["script1.json", "script2.json"]}

main file ("pluginsFile" variable is the content of "Plugins.json"):

/*I have a system that lets the user import the plugins file*/
loadedScripts = 0;
if (pluginsFile.include){
    for (i of pluginsFile.include){
        var scriptToAdd = document.createElement("script");
        scriptToAdd.src = pluginsFile.include[i];
        scriptToAdd.addEventListener("load", function(){
            loadedScripts++;
        })
        document.head.appendchild(scriptToAdd);
    }
    while (loadedScripts < document.querySelectorAll("head > script")){//Assume that I only have the scripts I want to add inside the head}
    //After all the scripts loaded
    console.log("loaded");
}

However, when I import the file, the while loop doesn't stop and the tab lags. I want to wait for all the scripts I insert into <head> to be loaded and then continue. I this possible?

5
  • 3
    Have you tried window.addEventListener('load', your-function-here)? Commented May 14, 2021 at 17:43
  • doesn't this event get triggered at the first load of the document? Commented May 14, 2021 at 17:43
  • document.querySelector() returns 1 single nodeElement and document.querySelectorAll() an array of elements. Maybe the problem is there in your while loop? And I would try this way: while (loadedScripts <= document.querySelectorAll("head > script").length) { ... } Commented May 14, 2021 at 17:44
  • Oops... Sorry, no, I have querySelectorAll() Commented May 14, 2021 at 17:45
  • You are burning your CPU here because you constantly query the number of loaded scripts. Your browser might not have the time to load scripts because it is busy with checking if all scripts haven been loaded. Try to put a sleep in your while loop (by using a Promise or switching to setInterval). Commented May 14, 2021 at 17:48

1 Answer 1

2

With Promises you can wait for each script to be loaded and do something after that.

Create a function that returns a Promise. Put the creation of your script tag, the setting of the src, listening for the load event, and appending the tag to the <head> inside of the promise. Modify the load event that it resolves the promise whenever the load event fires. Resolving tells the promise it is done.

const loadScript = src => new Promise(resolve => {
  const script = document.createElement('script');
  script.src = src;
  script.addEventListener('load', resolve);
  document.head.appendchild(script);
});

Then map over each file source in your pluginsFile.include array and call the function that loads the script inside of the promise. The result should now be an array of promises.

We'll want to wait before continuing until all promises in that array are resolved. We can do this with Promise.all(). The logic that comes after the Promise.all() in the then() method will be executed once all scripts have been loaded.

if (pluginsFile.include.length) {
  const loadingScripts = pluginsFile.include.map(loadScript);
  Promise.all(loadingScripts).then(() => {
    console.log('loaded');
  });
}
Sign up to request clarification or add additional context in comments.

2 Comments

OH MY GOD THANK YOU SO MUCH!!! I have been trying to fix this for 4 hours. I was scared to ask in StackOverflow because I had a history of asking low questions and you solved this in some minutes!!!
@Ath.Bar. You're very welcome. Good job posting your question regardless of previous posts! Keep it up!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.