Dynamically Loading Javascript Synchronously

Today I have been working on a new security challenge that meant that I had to load a number of javascript sources dynamically. Now there are multiple references to be found on Google on how to do this, however the challenge that I faced was the ability to load scripts in a specific order. This is unfortunately more difficult that it seems due to browser optimisation… let me give you an example.

In the case of jQuery and jQuery-UI, the order in which the scripts are loaded is important. This means that when developing a webpage, you would usually do something to the effect of:



Therefore forcing the browser to load each script sequentially. The problem however is presented when dynamically loading javascript using a method similar to:

var loadCount = 0;
var scripts = [
"http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js",
"http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js",
];

function loadJavascript(url) {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = url;

script.onreadystatechange = function() {
if (this.readyState == 'complete')
handler();
}

script.onload = handler;

if (typeof script != "undefined") {
document.getElementsByTagName("head")[0].appendChild(script);
}

return script;
}

function handler() {
loadCount++;
}

for(x = 0; x < scripts.length; x++) {
loadJavascript(scripts[loadCount]);
}

On first appearance, this script seems to work correctly. We do however encounter a problem when working with jQuery due to browser optimisations, as can be seen from this timeline screenshot:

You can see that both scripts are being downloaded simultaneously by the browser. This means that in the case of jQuery, every so often (usually determined by the file size, and speed of response from the server) you will see an error such as the follows:

The solution to this I have found lies in recursion. By taking our script above and making a slight modification, we can synchronously download each javascript file.

var loadCount = 0;
var scripts = [
"http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js",
"http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js",
];

function loadJavascript(url) {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = url;

script.onreadystatechange = function() {
if (this.readyState == 'complete')
handler();
}

script.onload = handler;

if (typeof script != "undefined") {
document.getElementsByTagName("head")[0].appendChild(script);
}

return script;
}

function handler() {
loadCount++;

// Use recursion here to load the next script when we know our last is successfully loaded
if (loadCount < scripts.length)
loadJavascript(scripts[loadCount]);
}


loadJavascript(scripts[loadCount]);

Now if we look at a timeline of our script loading, we can see that our browser is waiting for one script to finish downloading before progressing to the next.

Whilst this technique obviously has a performance impact when used for anything in a production environment, I have found it to be invaluable when dealing with dynamic loading of scripts such as jQuery.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s