jQuery getScript
Asked Answered
R

3

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]);
};
Redding answered 16/8, 2011 at 19:0 Comment(2)
Why are you using $.proxy? You aren't referring to this in the anonymous functionComplacent
It was my attempt at setting the correct context but it didn't seem to change anything.Redding
C
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
   );
}
Complacent answered 16/8, 2011 at 19:6 Comment(7)
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).Redding
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))Complacent
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.Redding
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.Redding
I've tested it and it works fine here (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?Complacent
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.Redding
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.Redding
I
9

You can do sync calls just do this:

$.ajaxSetup({async: false});
$.getScript('library.js');
$.ajaxSetup({async: true});
Indehiscent answered 16/8, 2011 at 19:4 Comment(3)
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, thoComplacent
I thought about this but would really prefer not to hold the UI up. Good idea though!Redding
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})Truditrudie
C
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
   );
}
Complacent answered 16/8, 2011 at 19:6 Comment(7)
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).Redding
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))Complacent
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.Redding
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.Redding
I've tested it and it works fine here (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?Complacent
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.Redding
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.Redding
Z
0

simple form:

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

usage:

getScript(a_url);
Zippel answered 19/8, 2014 at 13:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.