<script> 태그는 어디에 위치해야 할까?
브라우저의 구성 요소
렌더링 엔진은 HTML, CSS를 파싱한 결과물로 페이지를 화면에 표시한다. (대표적인 렌더링 엔진으로는 사파리의 webkit, IE의 trident, 파이어폭스의 Gecko, 크롬, 오페라, edge의 Blink(webkit에서 파생)가 있다.)
자바스크립트는 자바스크립트 해석기에서 해석한다.
브라우저의 동작 방식
- HTML을 읽기 시작
- HTML을 파싱
- DOM 트리 생성
- Render 트리(DOM tree + CSS의 CSSOM 트리 결합)가 생성
- Display에 표시
script를 html에 위치시키는 방법에는 script를 head 태그 안에 위치시키는 경우, body 태그의 맨 아래에 위치시키는 경우, async나 defer를 사용하는 경우가 있다.
1. head 태그 안에 위치시키는 경우
브라우저가 HTML 코드를 읽어내려오다가 <script> 태그를 만나게 되면, 해당 파일을 다운로드하고 실행시키기 위해 HTML을 읽어오는 과정을 잠깐 멈추게 된다. 그리고 해당 파일을 모두 다운로드하고 실행을 시킨 이후에 다시 나머지 HTML 코드를 읽게 된다.
이럴 경우, script 파일의 용량이 너무 크거나 갯수가 많다면 해당 파일을 다운로드하고 실행시키는데 많은 시간이 소요되므로 사용자가 화면을 보기까지 상당히 많은 시간이 걸릴 수 있다.
또한 js 파일 내부에 HTML에서 쿼리를 조회하고 조작하는 부분이 있을 때, 해당 쿼리 실행을 할 수 있는 HTML 코드가 js가 실행된 다음에 위치해있다면 오류가 발생할 수 있다.
2. body 태그의 맨 아래에 위치시키는 경우
브라우저가 HTML 코드를 처음부터 읽어내려오면서 모든 HTML코드의 파싱이 끝났을 때 script 태그에 쓰인 파일을 다운로드하고, 완료되면 파일을 실행하게 된다.
이는 파일을 다운로드하기 전 html 코드를 모두 읽기 때문에 사용자가 화면의 content를 빨리 볼 수 있다는 장점이 있지만, 만약 html 코드가 js에 의존적인 코드라면 사용자가 content를 보는 시점에 아직 완성되지 않은, 의미 없는 content를 볼 수 있다는 단점도 존재한다.
+ HTML 태그들 사이에 script 태그가 위치할 경우?
아래의 문제가 발생
- HTML을 읽는 과정에 스크립트를 만나면 중단 시점이 생기고 그만큼 display에 표시되는 것이 지연
- DOM 트리가 생성되기 전에 javascript가 생성되지 않은 DOM의 조작을 시도할 수 있음
따라서 body 태그 안에 script 태그를 위치시킬 경우, body 태그 최하단에 놓는 것이 가장 좋다.
3. async
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
<script async src="main.js"></script>
</head>
<body>
</body>
</html>
최근의 브라우저는 스크립트의 비동기 및 지연 특성을 지원한다. 이는 스크립트가 다운로드되는 동안 계속 구문 분석을 하는 것이 안전하다는 것을 브라우저네 알려준다. async 속성이 있는 스크립트는 비동기적으로 실행된다. 즉, 스크립트가 다운로드되는 즉시 브라우저가 차단되지 않고 실행된다.
HTML 코드를 파싱하다 script 태그를 만나면 html를 마저 파싱하는 동시에 script를 다운로드시킨다. 그리고 실행시키는데, 실행시키는 동안에는 html파싱이 멈추게 된다.
이는 js에 의존적인 웹을 좀 더 빨리 실행시킬 수 있다는 장점이 존재하지만, 결국에는 html파싱이 js파일을 실행시키는 동안 멈추게 되어 그냥 head부분에 넣는 경우에서 일어날 문제를 겪을 수 있다는 단점도 존재한다.
또한, 실행시켜야 할 script 태그가 여러개일 때, 순서에 상관없이 먼저 다운로드 받아지는 script를 먼저 실행시키기 때문에 해당 프로젝트가 script 파일의 실행 순서에 영향을 받는다면 문제가 될 수 있다.
4. defer
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
<script defer src="main.js"></script>
</head>
<body>
</body>
</html>
defer는 HTML을 파싱하다가 script 태그를 만나면 async와 마찬가지로 HTML을 파싱하면서 script는 동시에 다운로드만 시켜둔다.
async와 차이점은 HTML 파싱이 완료된 후에 script를 실행시킨다는 점이다.
이는 위의 방법들 중에서 가장 이상적이라고 할 수 있는데, HTML 파싱이 중간에 멈출 염려도 없고, 두 번째 방법(body의 끝에 위치하는 경우)의 단점도 개선시킬 수 있다.
여러개의 script 태그를 이용해도 미리 다운을 다 받고 HTML도 끝까지 파싱시킨 후에 순서대로 실행되기 때문에 async의 단점을 보완할 수 있다.
'FE > Javascript' 카테고리의 다른 글
[JS] 자바스크립트로 모멘텀(Momentum) 만들기 (0) | 2021.09.07 |
---|---|
[JS] filter 함수란? (0) | 2021.09.02 |
[JS] Array.from을 통한 배열 초기화 (0) | 2021.08.23 |
[JS] splice()란? - 배열 요소 추가/삭제/교체 (0) | 2021.08.13 |
[JS] substr(), substring(), slice()란? + 차이점 (0) | 2021.07.26 |