Speed Up Web Page Loading By Deferring Javascript

Written by Lucy Liu on 11 Apr 2012
30,344 Views • Techniques


Performance Level from BigStock

Deferring JavaScript execution is an efficient approach to accelerate web page loading and improve user experience on reading. From the true experience, migrating our website to a Softlayer dedicated server (Xeon 3360 Quadcore 2.83GHz & 4GB RAM) from an economic VPS plan only speeds website up by 20%, but deferring JavaScript execution helps 50% increase, seeing in the Google Webmaster Tool > Site Performance


The web page development is following the assumption that the web page can be rendered almost correctly without JS errors, even if all JS files are interrupted. Simply speaking, deferring JS execution follows these 2 rules,

  1. Execute inline JavaScript code after document ready, at least at the bottom of web page.
  2. Load external JavaScript files dynamically. If there are dependencies between multiple JS files, ensure main JS files loaded at the bottom of web page at least.

The following code snippet for a master page indicates how we do JS deferring in development.

<script type="text/javascript">// <![CDATA[
        _lazyLoadScripts = new Array();
        _lazyExecutedCallbacks = new Array();
// ]]></script>
<script type="text/javascript" src="/scripts/jquery-1.4.4.min.js"></script>
<script type="text/javascript" src="/scripts/website-lazy-load.js"></script>

In development, usually some nested web pages or modules depend on some external JS files or JS code execution. In this case, the variables "_lazyLoadScripts" and "_lazyExecutedCallbacks" are used, which are defined in the head of master page as the code snippet above.

See the following code snippet about how these two variables work in a nested page or module.

<script type="text/javascript">// <![CDATA[
    _lazyExecutedCallbacks.push(function ()
        // in the case you need to execute some scripts in a nested page or module.
        // don't execute them explicitly, but push them into the callback list.
// ]]></script>
<script type="text/javascript">// <![CDATA[
    // push the external JS files into the list for deferring loading.
// ]]></script>

The pushed JS execution in "_lazyExecutedCallbacks" and inserted external JS files in "_lazyLoadScripts" are all executed in "website-lazy-load.js" as following code snippet.

// dynamically load external JS files when document ready
// dynamically load external JS files when document ready
function loadScriptsAfterDocumentReady()
	if (_lazyLoadScripts && _lazyLoadScripts != null)
		for (var i = 0; i < _lazyLoadScripts.length; i++)
			var scriptTag = document.createElement('script');
			scriptTag.type = 'text/javascript';
			scriptTag.src = _lazyLoadScripts[i];
			var firstScriptTag = document.getElementsByTagName('script')[0];
			firstScriptTag.parentNode.insertBefore(scriptTag, firstScriptTag);

// Execute the callback when document ready.
function invokeLazyExecutedCallbacks()
	if (_lazyExecutedCallbacks && _lazyExecutedCallbacks.length > 0)
		for(var i=0; i<_lazyExecutedCallbacks.length; i++)

// execute all deferring JS when document is ready by using jQuery.
jQuery(document).ready(function ()


  1. A reasonable process to develop a web page is that first write HTML and CSS. Start to write JS for animation or other purposes after the web page works in browsers as the expectation.
  2. Don't bind events on HTML elements like onclick="...", but do it when the document is ready. This helps that there is no JS error if users click a button before JS files are loaded.
  3. If there are some external JS files you have to load site widely, write them in "website-lazy-load.js" and load them dynamically, such as Google Analytics tracking JS file, Google AdSense JS file, etc.
  4. This approach works for external CSS files as well, but don't do it for main CSS file.
Join the discussion

Comments will be moderated and rel="nofollow" will be added to all links. You can wrap your coding with [code][/code] to make use of built-in syntax highlighter.

vsync 12 years ago
Franco Averta 12 years ago
Thanks for this approach, and thanks @vsync for the new data