load javascript asynchronously using managedXHR

A nice explanation by Steve Souders at youtube.com/watch?v=52gL93S3usU mainly on loading JavaScript asynchronously.

We can try out each technique by referring to this page.

One of the common issue is the undefined error due to dependency between JavaScript files when scripts loaded asynchronously. For example when using jquery plugins, the core jquery file, followed by the plugins files and lastly the inline scripts for function initialization must be loaded in consecutive manner. One of the technique to solve this issue is by using managed XHR(assume all files are from the same domain).

Below are the snippets:

1.Put this snippet at the bottom of the page as inline code.
if ( "undefined" == typeof(ManagedXHR) || !ManagedXHR ) {
 var ManagedXHR = {};
}

ManagedXHR.Script = {
 queuedScripts: [],

 loadScriptXhrInjection: function(url, onload, bOrder) {
  var iQueue = ManagedXHR.Script.queuedScripts.length;
  if ( bOrder ) {
   var qScript = { response: null, onload: onload, done: false };
   ManagedXHR.Script.queuedScripts[iQueue] = qScript;
  }

  var xhrObj = ManagedXHR.Script.getXHRObject();
  xhrObj.onreadystatechange = function() { 
   if ( xhrObj.readyState == 4 ) {
    if ( bOrder ) {
     ManagedXHR.Script.queuedScripts[iQueue].response = xhrObj.responseText;
     ManagedXHR.Script.injectScripts();
    }
    else {
     var se = document.createElement('script');
     document.getElementsByTagName('head')[0].appendChild(se);
     se.text = xhrObj.responseText;
     if ( onload ) {
      onload();
     }
    }
   }
  };
  xhrObj.open('GET', url, true);
  xhrObj.send('');
 },

 injectScripts: function() {
  var len = ManagedXHR.Script.queuedScripts.length;
  for ( var i = 0; i < len; i++ ) {
   var qScript = ManagedXHR.Script.queuedScripts[i];
   if ( ! qScript.done ) {
    if ( ! qScript.response ) {
     // STOP! need to wait for this response
     break;
    }
    else {
     var se = document.createElement('script');
     document.getElementsByTagName('head')[0].appendChild(se);
     se.text = qScript.response;
     if ( qScript.onload ) {
      qScript.onload();
     }
     qScript.done = true;
    }
   }
  }
 },

 getXHRObject: function() {
  var xhrObj = false;
  try {
   xhrObj = new XMLHttpRequest();
  }
  catch(e){
   var aTypes = ["Msxml2.XMLHTTP.6.0", 
        "Msxml2.XMLHTTP.3.0", 
        "Msxml2.XMLHTTP", 
        "Microsoft.XMLHTTP"];
   var len = aTypes.length;
   for ( var i=0; i < len; i++ ) {
    try {
     xhrObj = new ActiveXObject(aTypes[i]);
    }
    catch(e) {
     continue;
    }
    break;
   }
  }
  finally {
   return xhrObj;
  }
 }
};

2.Call our external JavaScript files like this:


Inside the init.js, we can call the initialization codes. By using this technique all external files can be loaded asynchronously and at the same time it preserves the order the code execution.

We can use httpWatch to see the difference.

2 comments:

  1. Could you elaborate a bit more:"Inside the init.js, we can call the initialization codes."

    How do you do that?
    What needs to be inside the init.js?

    ReplyDelete
  2. Hi mollix,

    init.js is optional. It's where you put your custom js functions or if your need to initialize any jquery plugins.

    ReplyDelete