0

i am trying to lazy (dynamically) load javascript files in my webpage.

i have used this :

http://www.javascriptkit.com/javatutors/loadjavascriptcss.shtml

   function loadjscssfile(filename, filetype){
    if (filetype=="js"){ //if filename is a external JavaScript file
        var fileref=document.createElement('script')
        fileref.setAttribute("type","text/javascript")
        fileref.setAttribute("src", filename)
    }
    else if (filetype=="css"){ //if filename is an external CSS file
        var fileref=document.createElement("link")
        fileref.setAttribute("rel", "stylesheet")
        fileref.setAttribute("type", "text/css")
        fileref.setAttribute("href", filename)
    }
    if (typeof fileref!="undefined")
        document.getElementsByTagName("head")[0].appendChild(fileref)
}

loadjscssfile("myscript1.js", "js") //dynamically load and add this .js file
loadjscssfile("myscript2.js", "js") //dynamically load and add this .js file
loadjscssfile("myscript3.js", "js") //dynamically load and add this .js file

these 3 script are to be loaded in a sequence.

myscript3 is dependent on myscript2
and myscript2 is dependent on myscript1.

trying to load it in this way is behaving wierdly.

Looks like these are not loaded in the sequence intended and hence undefined errors are thrown at times and at times no error are thrown.

Am i doing something wrong.


Updated :

I am using this code to load the files in the correct sequence

 function loadjscssfile(filename, filetype) {
        if (filetype == "js") { //if filename is a external JavaScript file
            var fileref = document.createElement('script')
            fileref.setAttribute("type", "text/javascript")
            fileref.setAttribute("src", filename)
        }
        else if (filetype == "css") { //if filename is an external CSS file
            var fileref = document.createElement("link")
            fileref.setAttribute("rel", "stylesheet")
            fileref.setAttribute("type", "text/css")
            fileref.setAttribute("href", filename)
        }
        return fileref;
    }

    function loadSync(files, types) {
        if (typeof (files[0]) === 'undefined') return false;
        var script = loadjscssfile(files[0], types[0]);
        script.onload = function () {
            files.shift();
            types.shift();
            loadSync(files, types);
        }
        if (typeof script != "undefined")
            document.getElementsByTagName("head")[0].appendChild(script)
    }

    loadSync(['scripts/module3.base.js', 'scripts/module3.core.js', 'scripts/module3.init.js'], ['js', 'js', 'js']);
    console.log('this should get printed when all the three files are loaded');


But the console output is :

this should get printed when all the three files are loaded
scripts/module3.base.js:9 base is initialised
scripts/module3.core.js:6 core is initialised
scripts/module3.init.js:3 app is initialsed

Looks like the first call to loadSync is itself an Asynchronous call

ankur
  • 557
  • 1
  • 10
  • 37

3 Answers3

1

There are open source js which will ease your problem. You can use LABJS or RequreJS plugins.

Script loaders like LABJS, RequireJS will improve the speed and quality of your code.

You can preserve order of loading your script like this in LABJS.

$LAB.setOptions({AlwaysPreserveOrder:true})
.script("script1.js")
.script("script2.js")

OR

$LAB
.script("script1.js").wait()
.script("script2.js")

script2.js will wait untill script1.js is loaded.

I guess this will solve your problem.

Kaushik
  • 57
  • 5
  • It's important to note for LABjs that by "wait" we mean execution, not loading. All scripts are loaded as in parallel as possible for best performance, but their execution is sequenced to be in the proper order if need be. – Kyle Simpson May 27 '15 at 01:33
0

For HTML5 just use async attribute ( info at http://davidwalsh.name/html5-async )

Example of function for loading script with a optional callback option

function loadScript(url, callback) {
    if (!callback) callback = function () {};
    var script = document.createElement("script")
    script.type = "text/javascript";
    script.setAttribute("async", "true");

    if (script.readyState){  //IE
        script.onreadystatechange = function(){
            if (script.readyState == "loaded" ||
                    script.readyState == "complete"){
                script.onreadystatechange = null;
                callback();
            }
        };
    } else {  //Others
        script.onload = function(){
            callback();
        };
    }

    script.src = url;
    document.getElementsByTagName("head")[0].appendChild(script);
}

For a mixed solution:

function loadjscssfile(url, type, callback) {
    if (!type) {
        type = "js";
    }
    var node;
    if (type === "js") {
        var node = document.createElement("script")
        node.setAttribute("async", "true");
        node.type = "text/javascript";

        if (node.readyState){  //IE
            node.onreadystatechange = function(){
                if (node.readyState == "loaded" ||
                        node.readyState == "complete"){
                    node.onreadystatechange = null;
                    callback();
                }
            };
        } else {  //Others
            node.onload = function(){
                callback();
            };
        }

        node.src = url;
    } else if (type === "css") {
        var node = document.createElement("link")
        node.type = "text/css";
        node.setAttribute("rel", "stylesheet");
        node.setAttribute("async", "true");

        if (node.readyState){  //IE
            node.onreadystatechange = function(){
                if (node.readyState == "loaded" ||
                        node.readyState == "complete"){
                    node.onreadystatechange = null;
                    callback();
                }
            };
        } else {  //Others
            node.onload = function(){
                callback();
            };
        }
        node.href = url;
    }
    if (node) {
        document.getElementsByTagName("head")[0].appendChild(node);
    } else {
        callback(new Error("File not found"));
    }
}

Loading a list of files

function loadjscssfileList(arr_original, callback) {
    var arr = [];
    arr_original.forEach(function (v) {
        arr.push(v);
    });
    var next = function () {
        if (arr.length) {
            var file    = arr.shift();
            loadjscssfile(file[0], file[1], function () {
                next();
            });
        } else {
            callback();
        }
    };
    next();
};


// use without callback
loadjscssfileList([
    ["myscript.js","js"],
    ["style.css","css"],
    ["myscript2.js","js"]
]);

// use with callback
loadjscssfileList([
    ["myscript.js","js"],
    ["style.css","css"],
    ["myscript2.js","js"]
], function () {
    alert("loaded")
});
  • i cant use the callback model because that would require me to change the existing code base (javascript widgets, modules etc) to fit into the callback hell model. – ankur May 05 '15 at 15:21
  • I dont intend to load them asynchronously. The idea is to load them as if they were written in the desired sequence in the **** section of the html page – ankur May 05 '15 at 15:24
  • to execute the script from loaded file as it was written in head write: loadjscssfile("myscript.js","js"); content of myscript.js (function (window) { // code here }).apply(window); – Sergiu Gordienco May 05 '15 at 15:24
  • well, the intention is to load (say) 10 javascript files in a particular sequence (i.e. synchronously) so that the dependency chain is not broken (without using the callback hell) – ankur May 05 '15 at 15:29
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/77018/discussion-between-ankur-and-sergiu-gordienco). – ankur May 05 '15 at 15:33
  • I will add the final solution, thanks for explication – Sergiu Gordienco May 05 '15 at 15:35
-1

you can load them synchronously.

function get_contents(file){
   var xhr = new XMLHttpRequest();
   xhr.open('get', file, false);
   xhr.send();
   return xhr.responseText;
 }

function loadjscssfile(filename, filetype){
var content = get_contents(filename);
if (filetype=="js"){ //if filename is a external JavaScript file
    var fileref=document.createElement('script');
    fileref.setAttribute("type","text/javascript");
    fileref.innerHTML = content;
}
else if (filetype=="css"){ //if filename is an external CSS file
    var fileref=document.createElement("link")
    fileref.setAttribute("rel", "stylesheet")
    fileref.setAttribute("type", "text/css")
    fileref.innerHTML = content;
}
if (typeof fileref!="undefined")
    document.getElementsByTagName("head")[0].appendChild(fileref)
}

To load it externally:

there're 2 ways:

Callback as the another answer.

Or you can do this:

function loadjscssfile(filename, filetype){
    if (filetype=="js"){ //if filename is a external JavaScript file
        var fileref=document.createElement('script')
        fileref.setAttribute("type","text/javascript")
        fileref.setAttribute("src", filename)
    }
    else if (filetype=="css"){ //if filename is an external CSS file
        var fileref=document.createElement("link")
        fileref.setAttribute("rel", "stylesheet")
        fileref.setAttribute("type", "text/css")
        fileref.setAttribute("href", filename)
    }
    return fileref;
}

function loadSync(files,types){
    if(files[0] === 'undefined')return false; //if there's no files to load
    var script = loadjscssfile(files[0],types[0]); //load first file
    script.onload = function(){//after the script is loaded delete them and continue;
        files.shift();
        types.shift();
        loadSync(files,types);
    }
    if (typeof script !="undefined")
        document.getElementsByTagName("head")[0].appendChild(script)
}

loadSync(["myscript1.js","myscript2.js","myscript3.js"],['js','js','js']);
Omar Elawady
  • 3,300
  • 1
  • 13
  • 17
  • i am able to load files like this in the correct sequence. But now i cant see them in the Sources section of chrome developer tools (naturally cz now we are appending the markup) – ankur May 05 '15 at 15:20
  • that's because now you're adding the source of the file to inline script tag so the script is not external because it has not `src`. – Omar Elawady May 05 '15 at 15:23
  • i don't want that. I still want to be able to see them in the resources section. so that they remain in separate files (as they should be) – ankur May 05 '15 at 15:26
  • i am able to load the files in the correct sequence but i have a problem viewing them in the resources tab of chrome developer tools. **if** the javascript file that i am trying to load contains only an object with some values **(i.e. no function statements)** and if 1) the chrome developer tools are open or 2) the js file i am loading contains any function(){} then I am able to view the file in the Resources tab – ankur May 05 '15 at 16:00
  • there is one more issue. the loadSync call in itself is an asynchronous call. Please see my updated question – ankur May 05 '15 at 16:06
  • this function loads the 3 scripts in order.there is no way to load script externally and synchronously. – Omar Elawady May 05 '15 at 16:14
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/77024/discussion-between-ankur-and-omar-elawady). – ankur May 05 '15 at 16:16