Written by

When you include JavaScript on your webpage, the DOM rendering engine must first parse the data before displaying the page to the end-user.

That is unless you load in your JavaScript asynchronously. But which of the many ways to do this are best?

First, I'll start by using inline JavaScript to load in the external files. This will execute as soon as the DOM parser discovers the code.

<script>
var script = document.createElement("script");
script.src = "main.js";
document.getElementsByTagName("body")[0].appendChild(script);
</script>

ProTip: Only use <script src="main.js"></script> if you absolutely must execute your JavaScript files immediately. This will block page rendering until it's downloaded, parsed, and executed!

Now, let's postpone executing the code until page load.

<script>
window.onload = function() {
	var script = document.createElement("script");
	script.src = "main.js";
	document.getElementsByTagName("body")[0].appendChild(script);
};
</script>

Better, but I'm obsessed with performance these days. Let's go further.

<script>
window.onload = function() {
	var script = document.createElement("script");
	script.setAttribute("async", "async");
	script.setAttribute("defer", "defer");
	script.src = "main.js";
	document.getElementsByTagName("body")[0].appendChild(script);
};
</script>

Now that the async and defer attributes are on the generated <script> tags, the rendering engine will postpone any JavaScript downloading and execution until necessary (for the browsers that support these attributes, ahem Internet Explorer 😝). This allows the DOM parser focus on the critical rendering path with HTML and CSS.

Updated Code

During my tests, I discovered when loading a webpage over a choppy internet connection, the onload event may potentially never fire if you loose the connection between page request and page load. This is a problem that needed a different approach.

Here's what I came up with:

function deferScript(a) {
	try {
		window.requestAnimationFrame(a);
		/* For modern browsers. */
	} catch (b) {
		try {
			window.addEventListener("DOMContentLoaded", a);
			/* This will be executed slightly later than requestAnimationFrame, but will still work nicely. */
		} catch (b) {
			try {
				window.addEventListener("load", a);
				/* In case "DOMContentLoaded" is not supported. */
			} catch (b) {
				try {
					window.attachEvent("onload", a);
					/* For older versions of Internet Explorer. */
				} catch (b) {
					a();
					/* If all else fails, execute immediately. */
				}
			}
		}
	}
}

deferScript(function() {
	var script = document.createElement("script");
	script.setAttribute("async", "async");
	script.setAttribute("defer", "defer");
	script.src = "main.js";
	document.getElementsByTagName("body")[0].appendChild(script);
});

So far, this is working beautifully. The code is executed regardless of connection status. I've even implimented this very code into my blog.

Yaaaaaaassssss!!

So, how can you improve the performance of your own website? Very often, you can postpone loading in your JavaScript files until the browser is ready for them.

ProTip: Be careful when you load scripts asynchronously because they may load and execute out of order, causing parsing errors. If you absolutely must execute certain scripts in order, concatenate them into one file.

If you need help improving your website's loading speed, I'm more than happy to work with you. Just send me an email and we can talk about the details.

If you like what I've written, follow my updates on Facebook and Twitter. Or you can susbscribe to email updates. This blog is brand-new, so it would be super fantastic if you would share it with your friends and colleagues! Thanks for reading!

Life is too short for bad websites!

Read my bio