Home > database >  Dynamically load Javascript file one at a time
Dynamically load Javascript file one at a time

Time:04-20

I am creating a loader. Since I use Firebase, I need to load the specific script files dynamically in the exact order. Here are the code in my HTML files. JsPack.js is a loader that will load specific scripts one at a time.

        <script id="loader" src="./header/jsPack.js" resources="firebasejs;firebaseInit;firebaseRef;jQuery"></script>   

And here is my current jsPack.js file. This works perfectly in the exact order. However, it cannot load only specific scripts, and just loads all scripts at once.

// Dynamically loading dependancies
let firebasejs = {"url":"https://www.gstatic.com/firebasejs/4.3.1/firebase.js", "type": "text/javascript", "sync": false};
let firebaseInit = {"url":"./js/firebase_init.js", "type": "text/javascript", "sync": true};
let firebaseRef = {"url":"./js/firebase_ref.js", "type": "text/javascript", "sync": true};
let jQuery = {"url":"./js/jquery-3.2.1.js", "type": "text/javascript", "sync": true};
let bootStrap = {"url":"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js", "type": "text/javascript", "sync": false};

function loadingDependancies(target){
    return new Promise((resolve, reject) => {
        try {
            let script = document.createElement("script");
            script.type = target.type;
            script.async = target.async;
            script.src = target.url;
            document.body.appendChild(script);
        } catch (err) { reject(err) };
    });
};

loadingDependancies(firebasejs)
    .then(loadingDependancies(firebaseInit))
    .then(loadingDependancies(firebaseRef))
    .then(loadingDependancies(jQuery))
    .catch(err => {console.log(err)})

Now, I have changed it into something like this.

// Dynamically loading dependancies
let resources = document.getElementById("loader").getAttribute("resources")
let resourcesArr = resources.split(";");
// console.log(resourcesArr);

let list = {
    // JS Resources List
    firebasejs: {"url":"https://www.gstatic.com/firebasejs/4.3.1/firebase.js", "type": "text/javascript", "location": "body"},
    firebaseInit: {"url":"./js/firebase_init.js", "type": "text/javascript", "location": "body"},
    firebaseRef: {"url":"./js/firebase_ref.js", "type": "text/javascript", "location": "body"},
    jQuery: {"url":"./js/jquery-3.2.1.js", "type": "text/javascript", "location": "body"},
    bootStrap: {"url":"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js", "type": "text/javascript", "location": "head"}

    // CSS Resources List
};


function loadingDependancies(resourceName){
    new Promise((resolve, reject) => {
        try {
            let resource = list[resourceName];
            console.log(resourceName);
            let script = document.createElement("script");
            let placement = document.getElementsByTagName(resource.location)[0];
            script.type = resource.type;
            script.src = resource.url;
            placement.appendChild(script);
            console.log("Loaded: ", resource.url);
        } catch (err) { reject(err) };
    });
};

// const loadEachDependancy = async () => {
//     for (resourceName of resourcesArr) {
//         const x = await loadingDependancies(resourceName)
//         // console.log(x);
//     }
// }
// loadEachDependancy();

function forEachDependancy(arr, f){
    var i = 0;
    var nextPromise = function() {
        if (i >= arr.length) return;
        else {
            var newPromise = Promise.resolve(f(arr[i]));
            i  ;
            return newPromise.then(nextPromise);
        }
    }   
    return Promise.resolve().then(nextPromise);
}

forEachDependancy(resourcesArr, loadingDependancies);

It should have been working. However, all the scripts are loaded at once and the 2nd script cannot get the objects from the 1st. Right now, I do not know what is the problem with my codes. The page loads very fast , proving that those scripts are loaded at the same time. The 2nd script also returns error since it cannot get the objects from the 1st script. However, the console.log states that the scripts are loaded one at a time, which really confuses me.

Console

Please respond if you know what is the problem with my codes. Thank you in advance.


Update: onl oad() with async works perfectly. Thank you very much. I did not expect we could put async inside script. With this I will not have to use Promise at all.

enter image description here

CodePudding user response:

Use the script async attribute

Seems like the problem could be solved easily by setting the async attribute to false. This way the scripts load in order and Firebase works. If set to true then the scripts can load in unpredictable order based on size, location, etc. And Firebase may fail because firebase-app.js must always be loaded first. And in fact, you'll see those errors if you set async = true in the snippet.

  script.async = false;

Run the snippet to see the scripts load in order:

  [

    "https://www.gstatic.com/firebasejs/8.10.1/firebase-app.js",
    "https://www.gstatic.com/firebasejs/8.10.1/firebase-analytics.js",
    "https://www.gstatic.com/firebasejs/8.10.1/firebase-app-check.js",
    "https://www.gstatic.com/firebasejs/8.10.1/firebase-auth.js",
    "https://www.gstatic.com/firebasejs/8.10.1/firebase-firestore.js",
    "https://www.gstatic.com/firebasejs/8.10.1/firebase-functions.js",
    "https://www.gstatic.com/firebasejs/8.10.1/firebase-messaging.js",
    "https://www.gstatic.com/firebasejs/8.10.1/firebase-storage.js",
    "https://www.gstatic.com/firebasejs/8.10.1/firebase-performance.js",
    "https://www.gstatic.com/firebasejs/8.10.1/firebase-database.js",
    "https://www.gstatic.com/firebasejs/8.10.1/firebase-remote-config.js",
    "https://code.jquery.com/jquery-3.6.0.min.js",
    "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"

  ].forEach(src => {


    let script = document.createElement('script');
    script.src = src;
    
    // if set true the scripts load in any order and Firebase may fail 
    script.async = false;  
    
    script.onload = console.log(src);

    document.body.append(script);


  });
Loading scripts...

CodePudding user response:

I use this function to load script by order, it use onload event

function loadScript(src, callback) {
  var script = document.createElement("script");
  script.src = src;
  if (callback)
    script.onload = callback;
  var doc = document.head || document.body;
  doc.appendChild(script);
}

loadScript('https://www.gstatic.com/firebasejs/4.3.1/firebase.js', function() {
  console.log('firebase.js loaded');
  loadScript('https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js', function() {
    console.log('jquery.js loaded');
    console.log($('#test').val())
  });
})
<input id="test" value="777">

  • Related