Import JavaScript Using DOM Insertion.txt

The most common and efficient way to dynamically insert JavaScript is to use a DOM insertion technique. When the page loads, provide some basic JavaScript architecture, most likely namespace, DOM, and event management, plus a JavaScript import method (YUI has a loader utility YUI Loader and all 4 packages in ). Then as JavaScript is executed on the page and additional features are required, a JavaScript insert method should be called to append the needed functionality to the page. This allows the initial page load to be faster and requires the inclusion of additional JavaScript only if it is necessary, so bandwidth and server load is reduced. This technique can also be applied to CSS.

Today we will look at a basic implementation of JavaScript DOM insertion:

Example 1: DOM Insertion Function

var _importJavaScript = function(url, callback) {
	if (! _importJavaScript.headTag) {_importJavaScript.headTag = document.getElementsByTagName("head")[0];}
	if (_importJavaScript._importedScripts[url]) {return false;} // uniqueness check
	_importJavaScript._importedScripts[url] = true;
	var newScript = document.createElement(script),
		doCallback = true;

	newScript.type = text/javascript;
	newScript.onload=function(e) {
		if (doCallback) {
			doCallback = false;
			callback(e);
		}
	};

	newScript.onreadystatechange= function (e) {
		if (doCallback && (loaded === this.readyState || complete === this.readyState)) {
			doCallback = false;
			callback(e);
		}
	};

	newScript.src = url;
	_importJavaScript.headTag.appendChild(newScript);
	return true;
};

_importJavaScript._importedScripts = {};

The "_importJavaScript" function requires two parameters the URL of the JavaScript file to append to the page, and the callback method to execute when the file is loaded. When dynamically inserting JavaScript into the page, a callback must be provided, because the content of that file is loaded into the JavaScript engine asynchronously to the code that executed the "_importJavaScript" function. Inside the function the page head tag is found and cached, and each time the function executes a new script tag is created and appended to the head. The callback method is attached to the onload event, which, in most browsers, will fire as soon as the JavaScript is finished loading. Unfortunately, IE does not fire the onload event, instead it fires the onreadystatechange. The onreadystatechange event also fires each time the readyState property of the event changes, so once for loading and once of loaded, so we wrap the callback and check for the right state. I also check for completed, because a lot of similar examples on the web were using it, however, my personal experience is that the state is set to loaded not completed.

Note: An object "_importJavaScript._importedScripts" is now used as a hashmap to ensure each time the "_importJavaScript" is called, that the same JavaScript is not added twice. Consequently, I modified the function to return true when a script is imported and false when it already exists.

Note: In some browsers, such as Opera, both the onreadystatechange and onload event are fired. To handle this, I have added Boolean, doCallback, that checks to see if the callback has executed yet.

Example 2: Calling _importJavaScript

_importJavaScript(../assets/js/test/testObject.js, function() {
	YAHOO.util.testObject.run();
});

In Example 2 the _importJavaScript function pulls in the "testObject.js", and once it is loaded, calls a run method on that object. In this case, testObject is only accessed from inside of the callback, but it has been added to window, so any code on your page has access to it once the callback function executes. If there are many dependencies on testObject, creating a CustomEvent for the dependencies to subscribe to, and firing that CustomEvent as the callback, can simplify your code.

This technique is simple and effective. With a little planning a developer can drastically reduce the amount of JavaScript/CSS that needs to be included on a page and the overall performance of a site. Here is a simple dynamically imported script example.