14

I am trying to write an ultra simple solution to load a bunch of JS files asynchronously. I have the following script below so far. However the callback is sometimes called when the scripts aren't actually loaded which causes a variable not found error. If I refresh the page sometimes it just works because I guess the files are coming straight from the cache and thus are there quicker than the callback is called, it's very strange?

var Loader = function () {

}
Loader.prototype = {
    require: function (scripts, callback) {
        this.loadCount      = 0;
        this.totalRequired  = scripts.length;
        this.callback       = callback;

        for (var i = 0; i < scripts.length; i++) {
            this.writeScript(scripts[i]);
        }
    },
    loaded: function (evt) {
        this.loadCount++;

        if (this.loadCount == this.totalRequired && typeof this.callback == 'function') this.callback.call();
    },
    writeScript: function (src) {
        var self = this;
        var s = document.createElement('script');
        s.type = "text/javascript";
        s.async = true;
        s.src = src;
        s.addEventListener('load', function (e) { self.loaded(e); }, false);
        var head = document.getElementsByTagName('head')[0];
        head.appendChild(s);
    }
}

Is there anyway to test that a JS file is completely loaded, without putting something in the actual JS file itself, because I would like to use the same pattern to load libraries out of my control (GMaps etc).

Invoking code, just before the tag.

var l = new Loader();
l.require([
    "ext2.js",
    "ext1.js"], 
    function() {
        var config = new MSW.Config();
        Refraction.Application().run(MSW.ViewMapper, config);
        console.log('All Scripts Loaded');
    });

Thanks for any help.

6
  • In which browser & version are you testing this? Commented Jun 13, 2010 at 15:26
  • In the latest WebKit, does it in the latest dev version of Chrome as well :( Commented Jun 13, 2010 at 15:38
  • I can't reproduce this using Chromium 5.0.375.70, loading two scripts from a CDN and one from localhost (containing a function necessary to execute a line inside the callback function). But is the async flag really necessary? What happens if you comment s.async = true; out? Commented Jun 13, 2010 at 16:48
  • yeah true async just isn't required. thanks :) Commented Jun 13, 2010 at 17:21
  • 1
    @galambalazs the script is for an mobile web app, IE is fortunately not a concern :D Commented Jul 12, 2010 at 14:01

6 Answers 6

4

Just in case you find this useful, I've created an async utility library that would let you write the above code as:

var Loader = function () {}

Loader.prototype = {
    require: function (scripts, callback) {
        async.map(scripts, this.writeScript, callback);
    },
    writeScript: function(src, callback) {
        var s = document.createElement('script');
        s.type = "text/javascript";
        s.src = src;
        s.addEventListener('load', function (e) { callback(null, e); }, false);
        var head = document.getElementsByTagName('head')[0];
        head.appendChild(s);
    }
}

If you're doing lots of asynchronous calls it has some quite powerful features :)

http://caolanmcmahon.com/async.html

Sign up to request clarification or add additional context in comments.

Comments

4

What about jQuery....

$.getScript('abc.js'); 

Above code will load the "abc.js" script file asynchronously....

2 Comments

I am using the xui framework already and don't want to include the jQuery framework as well, it will just add extra weight :) Although I didn't know jQuery could do this, thanks!
getScript does not have a callback which is called once the script has been executed.
3

I recommend you use a tiny loader javascript like JcorsLoader (only 647B with Gzip)

JcorsLoader.load(
                "http://xxxx/jquery.min.js",
                function() {
                    $("#demo").html("jQuery Loaded");
                },
                "http://xxxx/jquery.cookie.js",
                function() {  
                    $.cookie('not_existing'); 
                }
            );

Load multiples js in parallel and execute in order without blocking DOMReady or onload.

https://github.com/pablomoretti/jcors-loader

Comments

2

There is nothing wrong with your code from what I can tell, this is just a bug in Chrome (it does it with window.onload also.)

I'd add it to the function that is triggered in the "load" function. If the variable exists, execute the JS code, but if it doesn't, use a setTimeout to check again in 500ms or so.

2 Comments

You can also test for a function being present: e.g., if you want to load jQuery this way, you can test for the $ function being present in global scope: if ('$' in window) /* do something */;
Thanks added this check as well :)
0

Like Aaron says there's a bug in chrome,but there are also problems on IE and other browsers.

I tryed different ways to create my lazy loader and i had a lot of problems:

  • adding a <script> tag : problems with script events(onload,onerror,etc.) in explorer and other browsers
  • reading a script with ajax and parsing the text(with eval,it's javascript so don't worry it's not evIl) : VERY difficult to debug (it's parsed as a single line without comments so you can't know what line gives you an error)
  • reading the script with ajax and adding a <script> tag with the text of the script: works very well on all browsers; you can create async and sync loading with the same function and you can also control very well errors,loading etc.(if you know the basics of ajax you should know how to handle variuous http state) and it's what i recommend.

Comments

0

jcors-loader.js not working in Internet Explorer...

Index.html

<html>
    <head>
    <script type="text/javascript" src="/js/jcors-loader.js"></script>
    <script>
        JcorsLoader.load(
                "js/jquery-1.8.0.js",
                "/js/alertme.js",
                function() {
                    $("#result").text("TEST OK");
                }
        );

    </script>
    </head>
    <body>
    <h1 id="result"></h1>
    </body>
    </html>

alertme.js

alert("Loaded");

This works fine in chrome and firefox it displays "TEST OK" and popup...But no message or alert in IE(7,8,9)...Any help will be appreciated.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.