7

I have a javascript widget that is included in a page by inserting a single script tag (as the application should be easiliy distributable):

<script type="text/javascript" src="loadMyWidget.js"></script>

loadMyWidget.js then needs to load multiple script files, which has to run in a certain sequence. I've tried to load them async by inserting script elements into the DOM, but that doesn't give me control of the sequence.

I also tried using head.js which is great for modern browsers, but I can't get it to work in IE7 and 8.

Minifying the scripts into one file is unfortunately difficult, as it is composed of a number of files from different projects and I wouldn't know when to update the script.

As simple as it seems, I need to load javascript files from javascript code in a certain sequence and get it to work in all browsers, including IE7 and 8.

Jørgen
  • 8,820
  • 9
  • 47
  • 67

5 Answers5

6

If you're using jQuery.getScript() you can use it as a $.when() to hold off execution until things have stopped loading.

If by "sequential execution" you mean that you need to load the requisites before execution the following will work

$(function(){
   $.when(
      $.getScript("/script1"),
      $.getScript("/scirpt2"),
      $.getScript("/script3")
}).done(function(){
    // do stuff with the contents of my new script files
});

If by sequential execution you mean that you need to execute files one after the other try this:

$.Deferred()
.then(function () { return $.getScript("/script1"); })
.then(function () { return $.getScript("/scirpt2"); })
.then(function () { return $.getScript("/script3"); })
.resolve();

Of course, this requires jQuery, which after your edits, this may not work for you.

Suggested Reading

Thinking Sites
  • 3,494
  • 17
  • 30
6

If you need vanilla JS, something like this could work:

function loadScripts(scripts, complete) {
    var loadScript = function( src ) {
        var xmlhttp, next;
        if (window.XMLHttpRequest)  {
            xmlhttp = new XMLHttpRequest();
        } else {
            try {
                 xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
            } catch(e) {
                return;
            }
        }
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                eval(xmlhttp.responseText);
                next = scripts.shift();
                if ( next ) {
                    loadScript(next);
                } else if ( typeof complete == 'function' ) {
                    complete();
                }
            }
        }
        xmlhttp.open("GET", src , true);
        xmlhttp.send();
    };

    loadScript( scripts.shift() );
}

loadScripts(['jquery.js','jquery.plugin.js'], function() {
    console.log('loaded');
});

Tested in Chrome, should work in IE too.

David Hellsing
  • 106,495
  • 44
  • 176
  • 212
  • This looks great. I figure this is how most of the AMD frameworks work internally. However, I can't get it to work in IE, and the behaviour is quite similar to my attempt with head.js. – Jørgen May 31 '12 at 14:22
  • What is not working in IE? (upgrading my VMware, will check in a minute). – David Hellsing May 31 '12 at 14:47
  • Just tried it in my IE9 with dev tools for IE7-8 versions and it passed my tests. What IE version are you having problems with? – David Hellsing May 31 '12 at 15:03
  • I'm also using IE9 dev tools. I get a error of an undefined variable, so I guess it's something about the sequence. I got it working with document.write, though I hate that solution. – Jørgen May 31 '12 at 15:10
4

I have run into this exact same issue and handled it with:

document.write('<script type="text/javascript" src="other1.js"></script>');
document.write('<script type="text/javascript" src="other2.js"></script>');

runSomeCode();

The code will be loaded and run synchronously. Pros: simple, light, cross browser compliant, no deps. Cons: ugly.

More details: https://stackoverflow.com/a/3292763/235179

Community
  • 1
  • 1
Josh Johnson
  • 10,729
  • 12
  • 60
  • 83
  • I know what you mean. Glad to help. – Josh Johnson May 31 '12 at 19:14
  • Unless I didn't understand right, this overwrites the whole document. So everything that was previously created in the DOM is lost. – Neptilo Dec 25 '14 at 11:04
  • @Neptilo: You didn't understand right. Nothing is lost. `document.write()` adds to the existing document. – recursive Sep 08 '16 at 15:27
  • This was so long ago. I don't remember why I thought it would overwrite the whole document. Looking back at my project, I think I ended up solving the issue by not executing any code in the included scripts, but only declaring classes and functions, and then only calling a "main" function from one of these scripts. – Neptilo Sep 09 '16 at 18:15
1

Have you tried require.js? http://requirejs.org/

Someth Victory
  • 4,492
  • 2
  • 23
  • 27
1
function loadScript(arrayOfUrlStrings, callback) {
  var numScripts = arrayOfUrlStrings.length;
  var count = 0;
  var headElement = document.getElementsByTagName('head')[0]

  function onLoad() {
    count += 1;

    if (count === numScripts) {
      callback();
    } else {
      addScript();
    }
  }

  function addScript() {
    var script = document.createElement('script');
    script.src = arrayOfUrlStrings[count];
    script.onload = onLoad;
    headElement.appendChild(script);
  }

  addScript();
}
spinners
  • 2,449
  • 3
  • 23
  • 34