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.

8
  • Have you tried RequireJS? Commented May 31, 2012 at 13:23
  • I've considered RequireJS, but I was hoping for a more simple solution. Commented May 31, 2012 at 13:24
  • Are you using jQuery? In that case you can try nesting $.getScript(). Commented May 31, 2012 at 13:27
  • I'm trying to load jQuery, so that won't help me much :P Thanks, though. Commented May 31, 2012 at 13:28
  • 1
    One script to rule them all... Commented May 31, 2012 at 13:59

5 Answers 5

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.

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

4 Comments

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.
What is not working in IE? (upgrading my VMware, will check in a minute).
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?
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.
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

4 Comments

This does not guarantee sequential execution order, does it?
No, I suppose not. I understood it slightly differently on first reading. Working on the edit...
Looks like a decent solution, if you're using jquery, that is :) +1
I'll admit, jquery's spoiled me. I don't do anything without it.
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

4 Comments

I know what you mean. Glad to help.
Unless I didn't understand right, this overwrites the whole document. So everything that was previously created in the DOM is lost.
@Neptilo: You didn't understand right. Nothing is lost. document.write() adds to the existing document.
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.
1

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

Comments

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();
}

1 Comment

If one script failed to load, all script after that will not be load.

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.