<script></script> normal, async, defer의 차이점
목차
- <script>의 normal 방식이 야기할 수 있는 문제점
- <script>의 파싱 및 실행 순서
- <script async>의 파싱 및 실행 순서
- <script defer>의 파싱 및 실행순서
1. <script>의 normal방식이 야기할 수 있는 문제점
<!-- #1 -->
<script>
console.log("script 실행">
</script>
<!-- #2 -->
<script src="{script url}"></script>
브라우저는 HTML을 읽다가 #1과 같이 <script>...</script>태그를 만나면 스크립트를 먼저 실행하고 DOM 생성을 멈춥니다. 또 #2와 같은 경우도 외부 스크립트를 다운받고 실행한 후에야 DOM생성을 하기 시작합니다.
이런 브라우저 동작방식은
- 스크립트에서 스크립트 아래에 있는 DOM요소에 접근을 할 수 없습니다.
- 페이지 위쪽에 용량이 큰 스크립트가 있는경우 스크립트 다운 및 실행할때까지 아래쪽 페이지를 볼 수 없습니다.
<div id="beforeScriptDiv">
<span> 스크립트 앞 콘텐츠 </span>
</div>
<script>
const beforeScriptDiv = document.getElementById('beforeScriptDiv');
const afterScriptDiv = document.getElementById('afterScriptDiv');
console.log(beforeScriptDiv); //<div id="xxx">...</div>
console.log(afterScriptDiv); // null
</script>
<div id="afterScriptDiv">
<span> 스크립트 뒤 콘텐츠 </span>
</div>
위의 문제를 해결하기 위해서 <script>...</script>를 화면 요소(<body></body>) 안의 맨 아래에 위치 시켜놓는 방법도 있습니다.
<body>
...화면 요소들
<script>....</script>
</body>
이러한 방법은 간단하고 가벼운 페이지들은 문제가 되진 않지만 HTML문서 자체가 아주 큰 경우,
브라우저가 HTML문서 전체를 다운로드 한다음에 스크립트를 다운 및 실행해서 페이지가 느려질 수 있습니다.
네트워크 속도가 빠른곳에서 접속하고 있다면 이러한 문제점은 체감하기에 어렵지만
네트워크 환경이 느린 곳에서 접속하면 느껴질 수 도있습니다.
이러한 문제는 <script>속성 async와 defer로 해결할 수 있습니다!
2. <script>의 파싱 및 실행순서
async, defer속성을 사용하지 않은 기본 normal 방식은 파싱 및 실행순서가 위에 그림과 같습니다.
HTML parsing 시작 -> <script>를 만나면 HTML parsing 중단 -> <script> 다운 및 실행 한 후 -> HTML parsing을 이어서합니다.
3. <script asnyc>의 파싱 및 실행순서
<script> asnyc 속성을 사용하면 페이지 파싱과 완전히 독립적으로 작동합니다.
defer스크립트와 마찬자기로 백그라운드에서 다운로드 됩니다.
또한, asnyc속성으로 불러오는 <script>가 여러개라면 순서에 상관없이 먼저 다운이 끝나는 순으로 실행되는 비동기 성격을 갖고 있습니다.
HTML parsing 시작 -> <script>를 만나도 HTML parsing 계속 -> 단, <script> 실행 할 때는 parsing 멈춤 -> HTML parsing을 이어서합니다.
<p>...스크립트 앞 콘텐츠...</p>
<script>
document.addEventListener('DOMContentLoaded', () => alert("DOM이 준비 되었습니다!"));
</script>
<script async src="heavy.js"></script>
<script async src="light.js"></script>
<p>...스크립트 뒤 콘텐츠...</p>
위에 코드를 예로 설명하자면,
- DOMContentLoaded 이벤트는 상황에 따라 비동기 스크립터 전이나 후에 실행됩니다. 정확한 순서를 예측할 순 없습니다.
- async속성은 비동기 성격으로 서로 기다리지 않습니다. 위치상으로 light.js가 heavy.js보다 밑에 있지만 light.js가 더 먼저 다운로드 되었기 때문에 먼저 실행됩니다. 이를 'load-first order'라고 부릅니다.
async 비동기 속성은 '방문자 수 카운터 나 광고 관련 스크립트' 처럼 각각 독립적인 역할을 하는 서드파티 스크립트에서
많이 사용합니다.
4. <script defer>의 파싱 및 실행순서
defer속성은 스크립트를 async와 마찬가지로 백그라운드에서 다운로드 합니다.
defer속성은 외부 스크립트에서만 유효합니다. (<script>에 src속성이 없으면 defer속성은 무시됩니다.)
HTML parsing 시작 -> <script>를 만나도 HTML parsing 계속 -> HTML parsing이 끝난 후 -> <script>실행 (DOMContentLoaded 이벤트 발생 전에 실행)
<p>...스크립트 앞 콘텐츠...</p>
<script>
document.addEventListener('DOMContentLoaded', () => alert("`defer` 스크립트가 실행된 후, DOM이 준비되었습니다!")); // (2)
</script>
<script defer src="https://heavy.js"></script>
<script defer src="https://light.js"></script>
<p>...스크립트 뒤 콘텐츠...</p>
다운로드는 작고 가벼운 스크립트 먼저 완료 되지만 실행은 정의한 순서대로 됩니다.
즉, defer 속성을 쓰면 순서가 지켜집니다.
heavy.js -> light.js -> DOMContentLoaded 순서대로 실행됩니다.
참고글: https://ko.javascript.info/script-async-defer
잘못된 정보에 대한 피드백은 언제나 환영입니다 (´▽`ʃƪ)♡
'내직업은 IT종사자 > HTML|CSS' 카테고리의 다른 글
[css] css selector(선택자) 종류, css 성능에 미치는 영향 (0) | 2023.05.09 |
---|---|
[css] css 방법론(oocss, bem, smacss) (0) | 2023.05.07 |
[html] a href="#" , javascript: void(0), javascript: ; 차이점, 무엇을 써야할까요? (0) | 2023.04.26 |
[html] a 태그 target="blank" 와 target="_blank" 차이 (3) | 2023.04.25 |
[html] display:none, visibility: hidden의 차이점 (0) | 2023.04.25 |