The HTML defer attribute
The HTML defer attribute holds a script until the document is parsed, then runs it before DOMContentLoaded fires. The file still downloads in parallel, and deferred scripts keep their source order even when a later one arrives first. It needs a src, as in <script defer src="app.js">.
Overview
The HTML defer attribute downloads an external script during parsing and runs it once parsing is complete. It belongs on <script> elements that have a src. Several deferred scripts run in the order they appear, even if a later file finishes downloading first.
Without defer or async, a classic script stops the parser at its tag until the file has downloaded and run. A deferred script instead sees the complete DOM, with document.readyState set to interactive, and DOMContentLoaded fires only after the last deferred script has run.
Deferred scripts also wait for stylesheets, although DOMContentLoaded itself doesn't. Because that event comes after the deferred scripts, a slow stylesheet in the head can hold up both.
The attribute only applies to scripts written in the page's HTML. A script you add with appendChild() ignores defer and can run as soon as it loads, even while the rest of the page is still being parsed.
Syntax
<script defer src="vendor.js"></script>
<script defer src="app.js"></script>
Values
| Value |
|---|
| Holds the script until the page has been parsed. |
Example
<p>Run order, with document.readyState at each step:</p>
<div role="status"><ol id="log"></ol></div>
<p>In the code, the deferred script sits between the two inline scripts and loads from a data: URL.</p>
<script>
function note(text) {
const li = document.createElement('li');
li.textContent = text + ' (' + document.readyState + ')';
document.getElementById('log').append(li);
}
function deferredRan() {
note('Deferred script');
}
note('First inline script');
document.addEventListener('DOMContentLoaded', function () {
note('DOMContentLoaded');
});
</script>
<script defer src="data:text/javascript,deferredRan()"></script>
<script>note('Second inline script');</script>
Best practices
- Put
deferon a classic script with a src when it needs the page's elements or another script. List such scripts in the order they must run, and use async for standalone ones. - Place deferred scripts in the <head>. A script at the end of the body may start downloading late when the page is long and the network is slow.
- Skip the
DOMContentLoadedwrapper in deferred code, since the elements are already parsed when it runs. Such a listener still fires as usual, so the wrapper only adds a step. - Leave
deferoff module scripts. Modules are deferred already, and defer on them is invalid HTML.























