8

I'm currently stuck using several JavaScript libraries that MUST load in a very specific order. Since jQuery's getScript() is asynchronous it starts downloading all of the scripts very quickly and, as they finish, executes them. Since they do not execute in order I get multiple errors coming from the libraries.

Unfortunately I cannot change or modify any of these libraries. What I'm attempting to do is use a method that downloads a JavaScript library and, in the callback, have it call itself until it's finished loading all of the libraries.

This works for the first file. When the second file comes around it loses context inside of the callback and I can't call my recursive method anymore.

Any ideas?

A paired-down version of the code:

function loadFiles (CompletedCallback) {
    var Files = getFiles(); // This is an array of js files to load
    var currentFileIndex = 0;

    function processFile (file) {
        $.getScript(file[currentFileIndex], $.proxy(function () {
            ++currentFileIndex;
            if (currentFileIndex === Files.length) {
                CompletedCallback();
            } else {
                processFile(Files[currentFileIndex]);
            }
        }, this);
    };

    processFile(Files[currentFileIndex]);
};
Kris
  • 1,789
  • 3
  • 18
  • 27

3 Answers3

9

You can do sync calls just do this:

$.ajaxSetup({async: false});
$.getScript('library.js');
$.ajaxSetup({async: true});
Michael D. Irizarry
  • 6,186
  • 5
  • 30
  • 35
  • 1
    Using synchronous loading could block UI interaction and other scripts running on the page. This could be a good solution if used in a Web Worker, tho – shesek Aug 16 '11 at 19:08
  • I thought about this but would really prefer not to hold the UI up. Good idea though! – Kris Aug 16 '11 at 19:23
  • Note that this will disable browser caching for the loaded file. I recommend adding `cache:true`. You can also use this on jQuery 1.12.0 or later: `$.getScript({url: "library.js",cache: true, async:false})` – oriadam Jul 05 '17 at 13:01
9

I'm not sure what's wrong with your code, but here's how I would do that:

function loadOrdered(files, callback) {
   $.getScript(files.shift(), function() {
       files.length
          ? loadOrdered(files, callback)
          : callback();
   });
}

edit, a nicer version:

function loadOrdered(files, callback) {
   $.getScript(files.shift(), files.length
       ? function(){loadOrdered(files, callback);}
       : callback
   );
}

or even nicer, if you don't care about old browsers or implement Function.prototype.bind yourself (with support for binding arguments too, and not just the this context):

function loadOrdered(files, callback) {
   $.getScript(files.shift(), files.length
       ? loadOrdered.bind(null, files, callback)
       : callback
   );
}
shesek
  • 4,584
  • 1
  • 28
  • 27
  • I'm trying to get your second option to work. It loads two javascript files but when it gets the callback after loading the second file, the context is completely gone (I placed a breakpoint in FireBug and this goes from the context I need to the context of the window). – Kris Aug 16 '11 at 19:38
  • If you need to preserve the context, you should be using `$.proxy` when passing the calback to `loadOrdered`, e.g. `loadOrdered(['a.js', 'b.js'], $.proxy(func, context))` – shesek Aug 16 '11 at 19:50
  • Thanks, I'll give this a shot. Since your code has everything passed around, the only reason I need any sort of context is to call loadOrderer() from the callback as it doesn't think it exists when the second callback occurs. – Kris Aug 16 '11 at 19:56
  • I have the same issue with this as well. When the callback happens a second time it loses the ability to touch and see the files and callback variables along with the loadOrdered method. They are simply gone when I set a breakpoint in FireBug and take a look. – Kris Aug 16 '11 at 20:03
  • I've tested it and it works fine here (http://paste2.org/p/1589765). I see no reason for loadOrderer() not to have access to itself... its probably something about your setup that causes it. Can you show the rest of the relevant code? – shesek Aug 16 '11 at 20:31
  • Oh... I'll take another look at it tomorrow to see where I went wrong. I'll update my post if necessary but the code above is almost exactly the same as the real code. I must be doing something funky then. Thanks for the help. – Kris Aug 17 '11 at 00:44
  • This is working, thanks! I'm not quite sure what was wrong with my code but I re-wrote the entire thing and it's working now. Puzzling but I don't care at this point. – Kris Sep 26 '11 at 14:06
0

simple form:

function getScript(url){ $.ajax({url: url, type: 'post', async: false}); }

usage:

getScript(a_url);
Behnam
  • 2,212
  • 2
  • 22
  • 32