13

I know that IE doesn't have a load event for <script> elements — is there any way to make up for that reliably?

I've seen some talk of things (e.g., requestState == "complete") but nothing very verifiable.


This is to be used so that code can be called after a script is finished loading, so that I don't have to use AJAX to load new sources (thus eliminating issues with cross-domain AJAX).

Timo Tijhof
  • 10,032
  • 6
  • 34
  • 48
Aaron Yodaiken
  • 19,163
  • 32
  • 103
  • 184
  • Can you just put a function call in the script you're loading that would run as the script is evaluated that would become your completion callback? – jfriend00 Jul 17 '11 at 16:48

3 Answers3

26

You can use a script loader like head.js. It has its own load callback and it will decrease load time too.


From the headjs code: (slightly modified to be more portable)

function scriptTag(src, callback) {

    var s = document.createElement('script');
    s.type = 'text/' + (src.type || 'javascript');
    s.src = src.src || src;
    s.async = false;

    s.onreadystatechange = s.onload = function () {

        var state = s.readyState;

        if (!callback.done && (!state || /loaded|complete/.test(state))) {
            callback.done = true;
            callback();
        }
    };

    // use body if available. more safe in IE
    (document.body || head).appendChild(s);
}
martin jakubik
  • 4,168
  • 5
  • 29
  • 42
Ilia Choly
  • 18,070
  • 14
  • 92
  • 160
  • 3
    I'm afraid I don't understand how a library can reduce load time caused by network latency :) – Aaron Yodaiken Jul 17 '11 at 18:02
  • browsers load ` – Ilia Choly Jul 17 '11 at 18:13
  • If code depends on all the script tags being present, there is little difference. – Aaron Yodaiken Jul 17 '11 at 18:20
  • 1
    how do you figure? All the scripts will load faster if you have them loading at the same time as opposed to one after another. Maybe I'm just bad at explaining, there's a good description on the headjs site. – Ilia Choly Jul 17 '11 at 18:23
  • 2
    This method allows you to control parallel and serial loading. It also allows you to know when they are completed. This is better than the browser which just loads from the top down synchronously and which will hold up content below. –  Nov 25 '12 at 18:49
  • Will the callback function fire if you update the .innerHTML instead of the .src....where is the documentation on how callback work for dynamic scripts? –  Jan 01 '13 at 23:46
  • +1 thanks! I updated my codebase kitgui.com to use this and works like a charm for IE. I was doing IE detection and their recent updates caused my code to not load the script. Now works. Kudos. – King Friday Apr 22 '13 at 20:27
  • 1
    If code in one script depends on code in another one, that's a sign you might want to be concatenating some of the scripts together if you can. – bosgood Sep 27 '13 at 02:42
4

I want to add that if you don't support IE7 and below, you don't need onreadystatechange stuff. Source: quircksmode.org

Simplified and working code from original answer:

function loadScript(src, callback) {    
    var s = document.createElement('script');
    s.type = 'text/javascript';
    s.src = src;
    s.async = false;
    if(callback) {
        s.onload = callback;     
    }
    document.body.appendChild(s);
}
Community
  • 1
  • 1
Dan
  • 55,715
  • 40
  • 116
  • 154
2

This is just an extension of ilia's answer. I used scriptTag like this: Works great:

    // these 3 scripts load serially.

    scriptTag(boot_config.DEPENDENCIES.jquery,function(){
        // jquery ready - set a flag
        scriptTag(boot_config.DEPENDENCIES.jqueryui,function(){
            // jqueryui ready - set a flag
            scriptTag(boot_config.DEPENDENCIES.your_app,function(){
                // your_app is ready! - set a flag
            });
        });
    });

    // these 2 scripts load in paralell to the group above

    scriptTag(boot_config.EXTERNALS.crypto,function(){
        // crypto ready - set a flag
    });

    scriptTag(boot_config.EXTERNALS.cropper,function(){
        // cropper ready - set a flag
    });