왜 body 태그 아래에 script를 놓아야할
문득 바닐라자바스크립트를 이용할 때 script태그를 꼭 아래에 넣었다. 그러다 요즘 면접 질문 등을 정리하는데 왜 아래에 놓아야할까 라는 의구심으로 정리하기로 했다.
브라우저는 HTML을 읽다가
<script>...</script> 에서 script 태그를 만나면 스크립트가 실행되고 해당 script 태그 이전에 생성된 DOM에만 접근이 가능하다.
이럴경우 브라우저의 동작 방식은 두 가지 중요한 이슈를 만든다.
- 스크립트에서는 스크립트 아래에 있는 DOM요소에 접근할 수 없다. 따라서 DOM요소에 핸들러를 추가하는 것과 같은 여러 행위가 불가능해진다.
- 페이지 위쪽에 용량이 큰 스크립트가 있는 경우 스크립트가 페이지를 막아버린다. 그리고 script가 실행될 동안에는 파싱을 멈추고, DOM트리 생성이 중지된다. 즉, 화면에 표시되는 것이 지연된다.
이런 부작용들을 피하기 위해서는 스크립트를 페이지 맨 아래 놓는 것이 하나의 방법이 될 수 있다.
<body>
...스크립트 위 콘텐츠들 ...
<script src="index.js"></script>
</body>
그런데 만약 HTML문서자체가 큰 경우 브라우저가 HTML문서 전체를 다운로드 한 다음에 스크립트를 다운받게 하면 페이지가 느려진다.
script속성에 defer 와 async가 있다.
defer
브라우저는 defer속성이 있는 스크립트(이하 defer 스크립트 또는 지연 스크립트)를 ‘백그라운드'에서 다운로드 한다. 따라서 defer 스크립트를 다운로드 하는 도중에는 HTML 파싱을 멈추지 않는다. 그리고 defer 스크립트 실행은 페이지 구성이 끝날 때까지 지연된다.
<body>
...스크립트 위 콘텐츠들 ...
<script src="index.js"></script>
<!-- 바로 볼 수 있다 -->
...스크립트 뒤 콘텐츠들 ...
</body>
- defer 스크립트는 페이지 생성을 절대 막지 않는다.
- defer 스크립트는 DOM이 준비된 후에 실행되긴 하지만 DOMContentLoaded 이벤트 발생 전에 실행된다.
defer 스크립트는 일반 스크립트와 마찬가지로 HTML에 추가된 순(상대순, 요소순)으로 실행된다. 따라서 길이가 긴 스크립트가 앞에, 길이가 짧은 스크립트가 뒤에 있어도 짧은 스크립트는 긴 스크립트가 실행될 때까지 기다린다.
팁! 브라우저는 성능을 위해 페이지에 어떤 스크립트들이 있는지 쭉 살펴본 후에 스크립트를 병렬적으로 다운로드한다. 스크립트 다운로드가 병렬적으로 진행되서 크기가 작은것이 먼저 다운로드 될지라도 순서는 실행되로 실행된다.
async
async 속성이 붙은 스크립트(이하 async 스크립트 또는 비동기 스크립트)는 페이지와 완전히 독립적으로 동작한다.
- async 스크립트는 defer 스크립트와 마찬가지로 백그라운드에서 다운로드된다. 따라서 HTML 페이지는 async 스크립트 다운이 완료되길 기다리지 않고 페이지 내 콘텐츠를 처리, 출력한다. (하지만 async 스크립트 실행중에는 HTML 파싱이 멈춘다)
- DOMContentLoaded 이벤트와 async 스크립트는 서로를 기다리지 않는다.
- 페이지 구성이 끝난 후 async 스크립트 다운로드가 끝난 경우, DOMContentLoaded는 async 스크립트 실행 전에 발생할 수 있다.
- 다른 스크립트들은 async 스크립트를 기다리지 않는다. async 스크립트 역시 다른 스크립트들을 기다리지 않는다.
실무에선 defer를 DOM 전체가 필요한 스크립트나 실행 순서가 중요한 경우에 적용합니다. async는 방문자 수 카운터나 광고 관련 스크립트같이 독립적인 스크립트에 혹은 실행 순서가 중요하지 않은 경우에 적용합니다.
정리
- async 속성이 명시된 경우 : 브라우저가 페이지를 파싱되는 동안에도 스크립트가 실행됨.
- async 속성은 명시되어 있지 않고 defer 속성만 명시된 경우 : 브라우저가 페이지의 파싱을 모두 끝내면 스크립트가 실행됨.
- async 속성과 defer 속성이 모두 명시되어 있지 않은 경우 : 브라우저가 페이지를 파싱하기 전에 스크립트를 가져와 바로 실행시킴.
참고자료 -
defer, async 스크립트
ko.javascript.info
코딩교육 티씨피스쿨
4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등
tcpschool.com