Deep dive into the murky waters of script loading by Jake Archibald
source: www.html5rocks.com
1. Include the script “as usual”
<script src="//other-domain.com/1.js"></script>
<script src="2.js"></script>
they’re downloaded in parallel and executed in order.They block rendering until they are executed. Since they can do things like
document.write
.2. IE defer attribute
The
defer
attribute tells IE (version 4) that the script won’t touch the DOM, so this script will not block the rendering.Unfortunately the script execution order is no longer guaranteed.
3. HTML5 async attribute
Similar to the
defer
attribute, it tells the browser that this script will not document.write
but again the execution order of the scripts is not guaranteed. If one script relies on another, you can get bugs.Ideally, you could just add your script tags and the browser would download them without blocking, but execute them in the order you specified them. This is not possible with plain HTML, you need libraries.
4. Libraries
- RequireJS: wrap your script in a callback, that the library would call in the correct order.
- others use
eval()
and XHR - labJS: add an invalid
type
attribute to you script (
<script type="script/cache" src="...”>
) Then once all of them are downloaded, labJS would change the MIME type and the browser would use its cache and execute them in the correct order. HTML5 broke this strategy, but LabJS has since been updated to count for this.
The problem, that an exta library also adds performance degradation (extra download, extra configuration, etc.)
5. Adding script programatically (dynamically)
Scripts added dynamically (by JavaScript) do not block the rendering, and you can set the
async
property to false
and execute them in order.
[
'//other-domain.com/1.js',
'2.js'
].forEach(function(src) {
var script = document.createElement('script');
script.src = src;
script.async = false;
document.head.appendChild(script);
});
This script can (should) be add the head
of the page. The browser of course has to understand the async
attribute.The disadvantages
It hides the script from preload scanners. You can add them back with the
link
element:
<link rel="subresource" href="//other-domain.com/1.js"><link rel="subresource" href="2.js”>
What if want one script (dependencies.js
) to download and execute and then all the rest (enhancements-1-10
) to execute in any order?async=false
does not solve this, as the the last enhancement-n.js
file will wait for all the other, non-related files to execute.