Question

I have created a small script loader function that will iterate over a javascript object populated with names of files in a directory. This is used to dynamically load Mustache templated files to create a page.

I created the javascript object to list the templates in the order I want them output to the page but sometimes when I load the page the elements are not in the right order. I know that in theory that $.each() 'does' iterate in order from top to bottom, but I'm wondering if there is some way I can explicitly force it to do in order to avoid the occasional improperly laid out page.

var loadModules = function(){
var templates = {
    1 : 'header',
    2 : 'about' 
}
$.each(templates, function(key, value) {
    $.getScript("js/modules/"+value+".js", function(){
        Init();
    });
});
}

This is a snippet of the code and from time to time when I load the page you will see the 'about' section appear above the 'header'. Is there any way I can stop this from happening or is it just a 'browser hiccup'?

I created the 'templates' object in order to specify the order of the page elements but it only seems to work most of the time.

Was it helpful?

Solution

Update if you don't want to change the structure of your templates so they can load better asynchronously then you may have to fall back a recursive loading approach. This will be relatively akin to synchronous loading of resources as you will be ensuring only one request is running at a time.

var templates = [
    'header',
    'about'
    /*....*/
];

//load up your templates 1 by 1 in a recursive loop
(function loadNextTemplate(index) {
    if(index >= templates.length) return; //base case
    $.getScript("js/modules/" + templates[index] + ".js")
     .then(function() {
        Init();
        loadNextTemplate(index + 1);
     });
})(0);

OTHER TIPS

Then you call $.getScript it send XMLHttpRequest, which use as async by default in $.ajax. $.getScript is the short calling of $.ajax for javascript files. So then the each is running it sends 2 async AJAX requests without guarantee in what order will requests ends.

If you what to call Init after 2 ajax requests ends, use jQuery Deffered/Promises pattern:

$.when($.getScript("js/modules/header.js"),  $.getScript("js/modules/about.js")).done(function(){
    Init();//Init will call after to AJAX requests ends, but without its order
});

If you need to load header.js always first and about.js must be the second, use this pattern like this:

$.when($.getScript("js/modules/header.js").then($.getScript("js/modules/about.js")).done(function(){
    Init();//header loads, after this about loads, after this Init will call
});

If you need to load 10-15 js files try to use AMD by requirejs. It need some special code wrappers functions, but requirejs is more useful. As for me using Deffered/Promises for 15 callbacks is not the hell.

Solved. Instead of using the always asynchronous $.getScript I opted to go with a simple ajax call setting the async value of the call to false. This always loads the scripts in the order they are listed in the array thanks to the for loop and async:false value of the ajax call. Eg:

var loadModules = function(){
//List modules in templates array in order you want them to appear in the DOM
var templates = [
    'header',
    'about' 
];


var i;
for (i=0; i<templates.length; ++i){
    $.ajax({
        url: "js/modules/"+templates[i]+".js",
        dataType: 'script',
        success: function(){
            Init();
        },
        async: false
    });
}

Thaks for all your help on this. I took a little bit from every answer/suggestion and applied them all so I don't know who's answer to mark as the right one..

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top