[Browser] <script> 태그의 적절한 위치
브라우저 동작 방식에 따른 Script 태그의 위치
앞의 글에서 말했듯, HTML은 맨 윗 줄 부터 차례대로 읽어 내려 가며 파싱이 되어진다. 그러다가 link 태그를 만나면 HTML파싱을 중단하고 CSS 요청, 응답 과정을 실행한다. 작업이 끝나면 중단된 HTML을 다시 읽고 DOM 트리를 완성하고 랜더 트리를 완성한다. 여기서 중간에 script태그를 만나게 되면 파싱을 중단한 뒤 제어 권한을 자바스크립트 엔진에게 넘기고 자바스크립트 코드를 실행한다. 그렇기 때문에 HTML 태그들 사이에 script 태그가 위치하면 두가지 문제가 발생한다.
1. HTML을 읽는 과정에서 스크립트를 만나면 중단 시점이 생기고 랜더링이 지연된다.
2. DOM 트리가 생성되기 이전에 자바스크립트가 생성되지도 않은 DOM의 조작을 시도 할 수 있다.
이 때문에 script 태그는 HTML 파일의 최 하단에 위치하는것이 좋다.
하지만 이러한 문제를 해결하기 위해 HTML5버전부터는 script 태그의 로딩 순서를 제어하거나 비동기적으로 불러오도록 할 수있는 속성이 추가되었다!
1. async
<script async src="script.js">
async 속성이 더해진 script 태그가 있을 때에는 HTML 파싱이 아래와 같이 작동한다.
async 속성이 더해진다면 렌더링 엔진이 script 태그를 만나더라도 HTML 파싱을 중단하지 않고 script 로드가 함께 이루어진다. script 로드가 끝나면 script가 실행되는 시점에 HTML 파싱이 잠시 중단되고, 실행이 끝나면 HTML 파싱이 재개된다.
async는 비록 javascript를 비동기적으로 로드 하더라도 결국 해당 코드를 실행 할 때에는 제어권이 렌더링 엔진에서 자바스크립트 엔진으로 넘어 가기 때문에 HTML 파싱이 중단된다.
2. defer
<script defer src="script.js">
async 속성 말고, defer 라는 속성이 있는데 이 속성을 사용한다면 아래와 같은 순서로 동작된다.
async의 속성과 달리, 로드도 비동기적으로 실행이 되고 모든 HTML 파싱이 완료 된 후에 JavaScript가 실행이 된다.
이렇게 script 태그에 async나 defer 속성을 추가하는 방법으로 로딩순서나 실행 순서를 제어 할 수도 있지만, script 내부에서 로딩순서를 제어할 수도 있다.
DOMContentLoaded 이벤트나 onload를 활용하면 JavaScript 자체에서 로딩 순서를 제어할 수 있다.
DOMContentLoaded: DOM생성이 모두 끝났을 때 발생하는 이벤트
window.onload: 문서에 포함된 모든 콘텐츠(img, script, css 등)가 모두 로드 된 후에 실행 되는 함수
(일반적으로 DOMContentLoaded가 먼저 불려지고 window.onload가 다음에 불려진다)