<script type="text/javascript" src="./script.js"></script>
현대 웹 브라우저에서 돌아가는 스크립트들은 대부분 HTML 보다 무겁다.
용량이 커서 이를 다운로드 받거나 처리하는 데 오랜 시간이 걸리게 된다.
웹 브라우저는 HTML의 앞부분 부터 읽다가 <script> 태그를 마주하면 DOM 생성을 멈춘다. src 속성이 있는 script 태그를 만났을 때도 마찬가지로 외부에서 스크립트를 다운 받고 실행한 후에 남은 페이지를 처리한다.
[이로 인해 발생할 수 있는 이슈들]
이 글을 보고 가장 먼저 생각해볼 수 있는 간단한 해결 방법은, script 태그를 페이지의 맨 아래에 놓는 것이다. DOM 생성도 막지 않고, 스크립트 또한 위에 있는 요소에 접근할 수 있다.
그러나, HTML문서 자체가 아주 큰 경우를 가정해보자. 브라우저가 HTML 문서 전체를 다운로드 하도록 한 후에, script를 다운 받도록 한다면 페이지는 굉장히 느려질 것이다. 네트워크 속도가 빠른 경우에는 크게 문제가 되지 않겠지만, 네트워크 환경이 열약한 경우 이러한 지연이 눈에 굉장히 잘 띌 것이다.
[해결 방법]
다행히도, script 태그가 가지고 있는 속성 defer
, async
을 이용해 이러한 문제를 해결할 수 있다.
우선, 브라우저는 defer 속성이 있는 스크립트(defer script 또는 지연 script 라고 부른다.)를 백그라운드에서 다운로드 한다.
따라서 script를 다운로드 하는 도중에도 DOM 생성(HTML 파싱)은 멈추지 않는다.
또한, defer script 실행은 페이지 구성이 모두 끝날 때 까지 지연된다.
다만 defer 속성은 외부 스크립트에만 유효하므로, src 속성이 없다면 defer 속성은 무시된다.
<p>...스크립트 앞 콘텐츠...</p>
<script defer src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>
<!-- 바로 볼 수 있네요! -->
<p>...스크립트 뒤 콘텐츠...</p>
<p>...스크립트 앞 콘텐츠...</p>
<script>
document.addEventListener('DOMContentLoaded', () => alert("`defer` 스크립트가 실행된 후, DOM이 준비되었습니다!")); // (2)
</script>
<script defer src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>
<p>...스크립트 뒤 콘텐츠...</p>
async 속성이 있는 script(async script 또는 비동기 script 라고 부른다.)는 페이지와 완전히 독립적으로 동작한다.
async script는 defer script처럼 백그라운드에서 다운로드 되며, HTML 페이지는 async 스크립트 다운이 완료되길 기다리지 않고 페이지 내 콘텐츠를 처리, 출력한다.(HTML parsing, DOM 생성)
<p>...스크립트 앞 콘텐츠...</p>
<script>
document.addEventListener('DOMContentLoaded', () => alert("DOM이 준비 되었습니다!"));
</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>...스크립트 뒤 콘텐츠...</p>