Async Script Loader with Callback

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

Usage

var l = new Loader();
l.require([
    "example-script-1.js",
    "example-script-2.js"], 
    function() {
        // Callback
        console.log('All Scripts Loaded');
    });

Comments

  1. User Avatar
    Mufeed Ahmad
    Permalink to comment#

    i request you to provide these code with demo… will help us a lot..

    thank you for your help.

  2. User Avatar
    Jerome Covington
    Permalink to comment#

    Thanks I just borrowed the writeScript method and trimmed it down a bit. Surprising how many times I do async loading and always forget the exact way to create the script element etc. Thanks!

  3. User Avatar
    Michiel Van Laere
    Permalink to comment#

    Maybe good to mention that “addEventListener” is not supported in IE8 or lower.
    They use “attachEvent”. You can support IE like this:

    if(s.addEventListener) {
    s.addEventListener(‘load’, function (e) { self.loaded(e); }, false);
    } else if(s.attachEvent) {
    s.attachEvent(‘load’, function (e) { self.loaded(e); }
    }

    Or if you are using jQuery you can use:

    jQuery(s).load(function(e) { self.loaded(e); });

    see: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener)”

    • User Avatar
      jockchou
      Permalink to comment#

      But script tag have not ‘load’ event. you should use ‘onreadystatechange’ to listene the scripts load.
      if (s.addEventListener) {
      s.addEventListner(‘load’, function(e) {
      //callback here
      }, false);
      } else {
      s.onreadystatechange = function() {
      if (s.readyState in {loaded: 1, complete: 1}) {
      //callback here
      }
      };
      }

      //some code

      function loadScript(url, callback){
      var script = document.createElement(“script”);
      script.type = “text/javascript”;
      script.charset = “utf8”;
      if (script.readyState) {//IE
      script.onreadystatechange = function() {
      if (script.readyState == ‘loaded’ || script.readyState == ‘complete’) {
      script.onreadystatechange = null;
      if (typeof callback === ‘function’) {
      callback();
      }
      }
      };
      } else {//other browers
      script.onload = function() {
      script.onload = null;
      if (typeof callback === ‘function’) {
      callback();
      }
      };
      }
      script.src = url;
      document.getElementsByTagName(“head”)[0].appendChild(script);
      }

  4. User Avatar
    David Vespoli
    Permalink to comment#

    @jockchou : your comment about using onreadystatechange instead as the trigger for the callback helped me get this working in IE8. Thanks!

  5. User Avatar
    Daniel Bammer
    Permalink to comment#

    This snippet didn’t really work out for me but jQuery.getScript() workes like a charm! https://api.jquery.com/jquery.getscript/

    • User Avatar
      Howard Brown
      Permalink to comment#

      I’m running on a local server while I investigate using the JQuery.UI.Datepicker plugin. The plugin requires a few patches and I’d like to wrap the datepicker’s library code load and the patches into a wrapper script that the page using the datepicker plugin can include, so allow the wrapper script to load the library, I’m trying to use the JQuery.getScript call, but I’m running into the following error:

      jquery-1.12.4.js:10254 XMLHttpRequest cannot load file:///D:/Users/.../Datepicker Widget.js?_=1469194829595.
      Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https, chrome-extension-resource.send @ jquery-1.12.4.js:10254
      Datepicker Widget.html:118 Uncaught TypeError: $(...).datepicker is not a function
      

      I believe that this is caused because my site is hosted locally, so doesn’t have a HTTP or HTTPS protocol prefix in the URL for the file that I’m trying to load. For local includes, is there a simple to I get this to work that doesn’t require that I register my own domain? After I am finished testing the datepicker my code will be moved to a server that has it’s own HTTP URL so this probably won’t be an issue then, but in the meantime or for other local projects I’d like to better understand how to make this all work.

    • User Avatar
      Flimm
      Permalink to comment#

      The success callback for jQuery.getScript is called once the script has been downloaded, but it’s not guaranteed to be called after the script has been executed.

  6. User Avatar
    Ankit G.
    Permalink to comment#

    A little advanced javascript loader based on this technique but with a little extra feature that it does not re download a script in any case. https://github.com/ankit31894/javascript-asynchronous-loader

    • User Avatar
      Tony
      Permalink to comment#

      Well that’s a shame, this turns out to be a 404, is it a private repo? Would be interesting to see how you’ve gone about this :)

    • User Avatar
      Ankit G.
      Permalink to comment#

      @Tony I have deleted that repository but If you want then I can repost it for you. Do you still want it?

    • User Avatar
      Tony
      Permalink to comment#

      Hey Ankit, That would be good thanks :) Although why not use github gist?

    • User Avatar
      Swaminathan
      Permalink to comment#

      @Ankit Please repost the repo. It would be very useful

  7. User Avatar
    Howard Brown
    Permalink to comment#

    Ankit G., I too would be very interested in seeing the repository that you deleted.

    Would you or anyone else know if these solutions, your and the $.getScript, will load JavaScript files and CSS files, too.

    Also, because I’m new to all of this please let me ask about when to use the call-back feature. If I use these methods to include a Javascript file in the page header area, do I execute it with the call-back, perhaps using a document.ready event, or must the execution be done in the page body?

    I currently am trying to load the JQuery.UI Datepicker library and some patching functions that modify some of the basic behaviours of datepicker, which requires that I run the library and patch functions before I can use them in my page body to create the datepicker controls. In my current code the datepicker’s library and JQuery are loaded with tags in the page header, but the patch functions are in tags in the page body, where they are created and then executed. I want to put the datepicker library load and the patch functions in a wrapper script file. The script could probably be loaded normally using the tag in the page header. This all would look sort of like the following:

        <!--
          The following wrapper files contains the $.getScript( 'JQuery.UI.Datepicker URL') and
          several patch functions that modify the datepicker object created by the getScript loader.
        --> 
    
    
    
        <!-- Code that uses the patched datepicker -->
        :
    
    
    
    The wrapper would be structured something like:
    /* *********************************************************
          Using $.getScript to load the JQuery.UI.Datepicker and
          then defining the patch functions needed to modify the
          datepickers behaviours.
         ********************************************************* */
    $.getScript( 'JQuery.UI.Datepicker URL' ...
    
    /* Define Patch functions */
    function Patch1() { ... }
     :
    function PatchN() { ... }
    
    /* Execute Patch functions */
    Patch1();
     :
    PatchN();
    
    /* End of Wrapper file */
    

    If structured this way and the datepicker and patching functions had code that was executed using the call-back feature, would this work?

    Alternatively, I could call the functions using the document.ready event using code in the wrapper file, if that was simpler.

    Thanks,
    Howard Brown

  8. User Avatar
    formigone
    Permalink to comment#

    Keep in mind that this is far slower than using a regular script tag with async + defer flags. See https://ibb.co/nyhJ3v

Submit a Comment

Posting Code

You may write comments in Markdown. This makes code easy to post, as you can write inline code like `<div>this</div>` or multiline blocks of code in triple backtick fences (```) with double new lines before and after.

Code of Conduct

Absolutely anyone is welcome to submit a comment here. But not all comments will be posted. Think of it like writing a letter to the editor. All submitted comments will be read, but not all published. Published comments will be on-topic, helpful, and further the discussion or debate.

Want to tell us something privately?

Feel free to use our contact form. That's a great place to let us know about typos or anything off-topic.

icon-closeicon-emailicon-linkicon-logo-staricon-menuicon-nav-guideicon-searchicon-staricon-tag