defer
The defer attribute tells the browser that it should go on working with the page, and load the script “in background”, then run the script when it loads.
- Scripts with
defernever block the page. - Scripts with
deferalways execute when the DOM is ready, but beforeDOMContentLoadedevent.
<script defer src="https://javascript.info/article/script-async-defer/long.js"></script><script defer src="https://javascript.info/article/script-async-defer/small.js"></script>
The small script downloads first, runs second
Browsers scan the page for scripts and download them in parallel, to improve performance. So in the example above both scripts download in parallel. The small.js probably makes it first.
But the specification requires scripts to execute in the document order, so it waits for long.js to execute.
The defer attribute is only for external scripts
The defer attribute is ignored if the <script> tag has no src.
async
The async attribute means that a script is completely independent:
- The page doesn’t wait for async scripts, the contents are processed and displayed.
DOMContentLoadedand async scripts don’t wait for each other:DOMContentLoadedmay happen both before an async script (if an async script finishes loading after the page is complete)- …or after an async script (if an async script is short or was in HTTP-cache)
- Other scripts don’t wait for
asyncscripts, andasyncscripts don’t wait for them.
- The page content shows up immediately:
asyncdoesn’t block it. DOMContentLoadedmay happen both before and afterasync, no guarantees here.- Async scripts don’t wait for each other. A smaller script
small.jsgoes second, but probably loads beforelong.js, so runs first. That’s called a “load-first” order.
Dynamic scripts
Dynamic scripts behave as “async” by default.
That is:
- They don’t wait for anything, nothing waits for them.
- The script that loads first – runs first (“load-first” order).
let script = document.createElement('script');script.src = "/article/script-async-defer/long.js";script.async = false;document.body.append(script);
For example, here we add two scripts. Without script.async=false they would execute in load-first order (the small.js probably first). But with that flag the order is “as in the document”:
function loadScript(src) {let script = document.createElement('script');script.src = src;script.async = false;document.body.append(script);}// long.js runs first because of async=falseloadScript("/article/script-async-defer/long.js");loadScript("/article/script-async-defer/small.js");
