현대의 웹사이트는 script가 HTML보다 처리할 데이터가 더 많아 무겁다.
컴퓨터는 코드를 읽을 때 script를 만나면 HTML을 읽는 것을 중지하고 우선 script 먼저 처리하는데 이는 인터넷속도가 빠른 경우 문제 없지만 그렇지 않은 경우 두 가지의 문제를 발생시킨다.
1. Scripts can’t see DOM elements below them, so they can’t add handlers etc.
2. If there’s a bulky script at the top of the page, it “blocks the page”. Users can’t see the page content till it downloads and runs.
<p>...content before script...</p>
<script src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>
<!-- This isn't visible until the script loads -->
<p>...content after script...</p>
해결 방법은 아래와 같으나 1번의 경우 HTML document의 길이가 긴 경우 피할 수 없는 delay가 발생한다
1. script
tag의 위치를 body end-tag 바로 위로 옮긴다
<body>
...all content is above the script...
<script src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>
</body>
async
와 defer
를 사용한다
브라우저는 defer
attribute가 있는 script
tag를 스킵하고 우선 HTML document부터 rendering한다. 이를 non-blocking이라고 한다.
<p>...content before script...</p>
<script defer src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>
<!-- visible immediately -->
<p>...content after script...</p>
<p>...content before scripts...</p>
<script>
document.addEventListener('DOMContentLoaded', () => alert("DOM ready after defer!"));
</script>
<script defer src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>
<p>...content after scripts...</p>
DOMContentLoaded
event handler waits for the deferred script. It only triggers when the script is downloaded and executed.<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>
⚠
defer
attribute는 external script에서만 사용 가능하다. 다른 말로src
attribute가 없는script
tag는 사용 불가.
async
attribute 또한 defer
처럼 non-blocking 속성을 가지고 있다. 하지만 중요한 차이점이 있는데 바로 종속적이지 않다는 점이다. completely independent
In other words, async scripts load in the background and run when ready. The DOM and other scripts don’t wait for them, and they don’t wait for anything. A fully independent script that runs when loaded.
<p>...content before scripts...</p>
<script>
document.addEventListener('DOMContentLoaded', () => alert("DOM ready!"));
</script>
<script async src="https://javascript.info/article/script-async-defer/long.js"></script>
<script async src="https://javascript.info/article/script-async-defer/small.js"></script>
<p>...content after scripts...</p>
DOMContentLoaded
는 async
전,후 언제라도 일어날 수 있다. no guarantees here.async
의 "load-first"oder에 따라 small.js
는 long.js
밑에 위치하지만 먼저 load된다면 defer
와는 다르게 먼저 실행된다. 비종속성async
script는 이러한 비종속성떄문에 독립적인 third-party script( 예를 들면, google analytics나 ads )와 함께 사용된다Order | DOMContentLoaded | |
---|---|---|
async | Load-first order. Their document order doesn’t matter – which loads first runs first | Irrelevant. May load and execute while the document has not yet been fully downloaded. That happens if scripts are small or cached, and the document is long enough. |
defer | Document order (as they go in the document). | Execute after the document is loaded and parsed (they wait if needed), right before DOMContentLoaded. |
In practice, defer is used for scripts that need the whole DOM and/or their relative execution order is important.
And async is used for independent scripts, like counters or ads. And their relative execution order does not matter.
⚠ Page without scripts should be usable
Please note: if you’re using defer or async, then user will see the the page before the script loads.
In such case, some graphical components are probably not initialized yet.
Don’t forget to put “loading” indication and disable buttons that aren’t functional yet. Let the user clearly see what he can do on the page, and what’s still getting ready.