4

I have some js scripts that I load into my main.js before I start the rest of my code. However during testing it came to my attention that sometimes it creates the following reference error (1 in 8 pageloads or something).

ReferenceError: createContainer is not defined

Now, the only reason that I can think of that I get this error is that when I execute the startScript() function, not all my files are loaded or fully accesable.

Now, perhaps I'm going about this all wrong for including other .js files into my main.js, so I'd like to hear your thoughts about this.

The main.js looks like this:

$(document).ready(function() {

    //sets and array of files that should be loaded before anything every happens
    var arrFilesToLoad = [  'scripts/global/variables.js',
                            'scripts/global/objects.js',
                            'scripts/global/classes.js'];
    var _error;

    //walks through the array of items that should be loaded and checks for fails
    $.each(arrFilesToLoad , function (key) {
        $.getScript(arrFilesToLoad[key])
            //when a file is loaded with succes
            .done(function () {
                //on default send a message to the console
                console.log(arrFilesToLoad[key] + 'loaded succesfully');
                //if every item is loaded start the script
                if(key == (arrFilesToLoad.length - 1)){
                    startScript();
                }
            })
            //when a file fails to load
            .fail(function () {
                //add the file that failed to load to a string message
                _error += arrFilesToLoad[key] + " - failed to load. \n";
                //show an alert with what file failed to load
                if(key == (arrFilesToLoad.length - 1)){
                    alert(_error);
                }
            });
    });

    function startScript () {
        //set a variable which contains a function that returns a DIV with styling
        var oContainer = createContainer();
        var oMainMenu = new Menu(arrMainMenu);
        $(oContainer).append(createMenu(oMainMenu));
        $('body').append(oContainer);
    }

});
galath
  • 5,009
  • 10
  • 27
  • 39
  • The file in which `createContainer` is defined is not yet loaded at the moment of the function call. – GuyT Jul 17 '15 at 09:08
  • Is `createContainer()` defined in one of the scripts you load? If so, which one? – Rory McCrossan Jul 17 '15 at 09:08
  • 1
    @RoryMcCrossan It has to be defined in one of the files because it only happens 1 out of 8 times. – GuyT Jul 17 '15 at 09:09
  • 1
    In your code, `key` in done callback should always be the last one set by `each` loop. A closure would fix it. That's said, Rory's answer would be better – A. Wolff Jul 17 '15 at 09:19

1 Answers1

4

The issue is because you're loading 3 scripts and presumably only one of them holds the createContainer() function, yet you execute your code when the last request has loaded. This means that you've got a race condition. The last request that was made is not guaranteed to be the last one that is completed. If the other scripts are still being loaded as the final request is completed, you'll see this error.

You can amend your logic so that the callback is only executed once all the scripts have loaded. Try this:

var requests = [];
$.each(arrFilesToLoad , function (key) {
    requests.push($.getScript(arrFilesToLoad[key]));
});

$.when.apply(this, requests)
    .done(startScript)
    .fail(function() {
        console.log('one or more scripts failed to load');
    });

function startScript() {
    var oContainer = createContainer();
    var oMainMenu = new Menu(arrMainMenu);
    $(oContainer).append(createMenu(oMainMenu));
    $('body').append(oContainer);
}
Rory McCrossan
  • 306,214
  • 37
  • 269
  • 303
  • Works like a charm, I've refreshed the page several times and it shows the content as I expect every time. Could you explain to me how this code works, as I am fairly new to JQuery. – Geert Kamps Jul 17 '15 at 09:19
  • 1
    Glad to help. This is similar to you original code, the difference is that it stores the promise objects returned by `$.getScript` in an array, which is then provided to `$.when`. This means that instead of the `done()` callback being executed for each finished request, it executes once when all requests have completed. – Rory McCrossan Jul 17 '15 at 09:23
  • I see, well thanks for your quick and timely response. – Geert Kamps Jul 17 '15 at 09:46