[JavaScript] script 태그의 위치와 async, defer
브라우저는 html 파일을 위에서부터 차례로 읽어 내려가며 parsing(분석)한다.
parsing 도중에 script 태그를 만나면 해당 script를 다운로드 받기 시작하는데,
만나게 되는 script 태그의 위치에 따른 장단점을 살펴보겠다.
1. <head>의 내부
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
<script src="main.js"></script>
</head>
<body>
...
</body>
</html>
브라우저가 html 파일을 위에서부터 차례로 읽어내려가다가 <script>를 만나면 HTML parsing을 멈추고 서버에서 자바스크립트 파일을 다운로드 하기 시작한다. js 파일 다운로드가 끝나면 js를 실행하고, 그 뒤에 잠시 멈춰두었던 HTML parsing을 다시 시작한다. 이 방식은 js 파일의 크기가 너무 크거나 네트워크가 느리면 사용자가 완전한 웹사이트를 보는 데까지 시간이 오래 걸린다.
2. <body> 내부의 마지막 줄
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
...
<script src="main.js"></script>
</body>
</html>
이 위치에 작성하면 HTML parsing이 완료된 다음 js 파일 다운로드를 시작하므로 사용자가 HTML 콘텐츠를 빨리 볼 수 있다는 장점이 있지만, 콘텐츠가 js에 의존하고 있다면 의미 있는 콘텐츠를 보기까지 js의 다운로드와 실행을 기다려야 한다는 단점이 있다.
3. async
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
<script async src="main.js"></script>
</head>
<body>
...
</body>
</html>
script 태그에 aync를 작성하고 head 태그에 넣는 방법도 있다. async는 boolean 타입이라 async="true"로 적을 필요없이 async만 적어주면 된다. async를 작성하면 위에서부터 html을 parsing 하던 브라우저가 script 태그를 만나고 parsing과 js 다운로드를 같이 한다. js 다운로드가 완료되면 js를 실행하고 js가 실행되는 동안은 HTML parsing이 중지되며 js 실행이 끝나면 parsing을 다시 시작한다.
HTML parsing과 js 다운로드가 같이 진행되므로 다운로드 시간을 절약한다는 장점이 있다.
하지만, HTML parsing이 완료되기 전에 js가 실행되므로 js에 아직 생성되지 않은 DOM요소를 참조하는 코드가 있다면 오류의 위험성이 있으며 js를 실행하기 위해 중간에 HTML parsing을 중지하므로 사용자가 완전한 페이지를 보는데 시간이 걸린다.
async가 작성된 script 태그가 복수인 경우도 살펴보겠다.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
<script async src="a.js"></script>
<script async src="b.js"></script>
<script async src="c.js"></script>
</head>
<body>
...
</body>
</html>
aync가 작성된 script 태그가 복수인 경우에는, 정의된 script 태그의 순서에 상관없이 다운로드가 먼저 완료된 순서대로 실행된다. 각각의 js 파일이 실행될 때마다 HTML은 중지와 재시작을 반복하게 되며, js 파일이 순서에 의존적이어서 b.js의 올바른 실행에 a.js가 필요한 상황이라면 문제가 생길 수 있다.
4. defer
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
<script defer src="main.js"></script>
</head>
<body>
...
</body>
</html>
defer 또한 async처럼 작성해주면 된다. defer는 parsing을 하다가 script태그를 만나면 parsing과 js 다운로드를 병렬적으로 실행하고 parsing이 끝나면 js 다운로드가 완료되는대로 js를 실행한다. HTML parsing을 진행하는 동안 js 다운로드를 모두 해놓고 HTML parsing이 끝나자마자 js를 실행하므로 사용자가 완전한 페이지를 보게 하는 데에 가장 좋은 선택지인 것 같다.
defer가 작성된 태그가 복수일 때도 살펴보겠다.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
<script defer src="a.js"></script>
<script defer src="b.js"></script>
<script defer src="c.js"></script>
</head>
<body>
...
</body>
</html>
HTML parsing이 완료되기 전에 필요한 js 파일들을 모두 다운로드 받아놓고 HTML parsing이 완료되는대로 정의한 script 태그의 순서를 따라 실행된다.
참고: 드림코딩 by 앨리 https://www.youtube.com/watch?v=tJieVCgGzhs