ControlJS part 1: async loading
Controlling download and execution
Controlling how scripts are downloaded is a popular practice among performance-minded developers. The issue is that when scripts are loaded the normal way (
ControlJS: how to use it
To use ControlJS you need to make three modifications to your page.
Modification #1: add control.js
var cjsscript = document.createElement('script'); cjsscript.src = "control.js"; var cjssib = document.getElementsByTagName('script'); cjssib.parentNode.insertBefore(cjsscript, cjssib);
Modification #2: change external scripts
The next step is to transform all of the old style external scripts to load the ControlJS way. The normal style looks like this:
The SCRIPT element’s TYPE attribute needs to be changed to “text/cjs” and the SRC attribute needs to be changed to DATA-CJSSRC, like this:
<script type="text/cjs" data-cjssrc="main.js"><script>
Modification #3: change inline scripts
to “text/cjs”, like this:
<script type="text/cjs"> var name = getName(); <script>
That’s it! ControlJS takes care of the rest.
ControlJS: how it works
Your existing SCRIPTs no longer block the page because the TYPE attribute has been changed to something the browser doesn’t recognize. This allows ControlJS to take control and load the scripts in a more high performance way. Let’s take a high-level look at how ControlJS works. You can also view the control.js script for more details.
We want to start downloading the scripts as soon as possible. Since we’re downloading them as an IMAGE or OBJECT they won’t block the page during the download phase. And since they’re not being downloaded as a SCRIPT they won’t be executed. ControlJS starts by finding all the SCRIPT elements that have the “text/cjs” type. If the script has a DATA-CJSSRC attribute then an IMAGE (for IE and Opera) or OBJECT (for all other browsers) is created dynamically with the appropriate URL. (See Stoyan’s post for the full details.)
By default ControlJS waits until the window load event before it begins the execution phase. (It’s also possible to have it start executing scripts immediately or once the DOM is loaded.) ControlJS iterates over its scripts a second time, doing so in the order they appear in the page. If the script is an inline script the code is extracted and evaluated. If the script is an external script and its IMAGE or OBJECT download has completed then it’s inserted in the page as a SCRIPT element so that the code is parsed and executed. If the IMAGE or OBJECT download hasn’t finished then it reenters the iteration after a short timeout and tries again.
There’s more functionality I’ll talk about in later posts regarding document.write and skipping the execution step. For now, let’s look at a simple async loading example.
To show ControlJS’s async loading capabilities I’ve created an example that contains three scripts in the HEAD:
- main.js – takes 4 seconds to download
- an inline script that references symbols from main.js
- page.js – takes 2 seconds to download and references symbols from the inline script
I made page.js take less time than main.js to make sure that the scripts are executed in the correct order (even though page.js downloads more quickly). I include the inline script because this is a pattern I see frequently (e.g., Google Analytics) but many script loader helpers don’t support inline scripts as part of the execution order.
Async withOUT ControlJS is the baseline example. It loads the scripts in the normal way. The HTTP waterfall chart generated in IE8 (using HttpWatch) is shown in Figure 1. IE8 is better than IE 6&7 – it loads scripts in parallel so main.js and page.js are downloaded together. But all versions of IE block image downloads until scripts are done, so images 1-4 get pushed out. Rendering is blocked by scripts in all browsers. In this example, main.js blocks rendering for four seconds as indicated by the green vertical line.
Figure 1: Async withOUT ControlJS waterfall chart (IE8)
Figure 2: Async WITH ControlJS waterfall chart (IE8)
The ControlJS project
ControlJS is open source under the Apache License. The control.js script can be found in the ControlJS Google Code project. Discussion topics can be created in the ControlJS Google Group. The examples and such are on my website at the ControlJS Home Page. I’ve written this code as a proof of concept. I’ve only tested it on the major browsers. It needs more review before being used in a production environment.
Only part 1