Front-end/깊게 파고들기

<script>는 정말 body 뒤에 들어가야 하는가

아지송아지 2022. 4. 6. 13:41
<body>
	...
	<script></script>
<body>

웹 개발을 할 때 <body>태그 제일 끝에 <script>태그를 넣고는 합니다.

html이 모두 렌더링 된 다음에 script를 실행해야 오류가 발생하지 않기 때문입니다.

저 또한 처음 자바스크립트를 배울 때 이렇게 배웠습니다.

 

위 코드처럼 작성하여도 큰 문제는 없지만, 프로젝트가 커지면 문제가 발생할 수 있습니다.

html 파일의 사이즈가 커질수록 스크립트의 다운받는 시점과 실행되는 시점이 지연됩니다.

 

이 방법을 해결하기 위해서는 defer, async 속성을 넣으면 됩니다.

 

defer


<head>
	<script defer src="./script.js"></script>
</head>

브라우저는 defer속성이 있는  스크립트는 백그라운드에서 다운로드합니다.

따라서 스크립트를 다운로드하며 html 파싱을 계속합니다. 그리고 페이지 구성이 끝날 때까지 실행을 지연시킵니다.

 
 
이외에 defer는 아래와 같은 특징들이 있습니다.
 
 

1. `DOMContentLoaded`보다 먼저 실행됩니다.

document.addEventListener('DOMContentLoaded', () => {
	console.log("load!")
});
 
"DOMContentLoaded"속성은 DOM트리가 완성되고 defer스크립트가 실행된 후에 실행됩니다.
 
 
 

2. html에 추가된 순으로 실행하기 때문에 먼저 다운로드 되었다고 해서 먼저 실행되지는 않습니다.

<script defer src="./large.js"></script>
<script defer src="./small.js"></script>
large.js는 5초, small.js는 1초의 다운로드 시간이 걸린다고 가정해봅시다.
small이 먼저 다운로드 되어도 실행은 large이후에 실행됩니다.
 
 
 
 

3. 외부 스크립트에만 유효합니다.

src속성이 없으면 defer 속성은 무시됩니다.

 

 

 

async


<script async src="./script.js"></script>

defer와 마찬가지고 백그라운드에서 다운로드됩니다.

async가 다운받을 동안은 html 파싱이 계속되지만 async 실행중에는 html 파싱을 멈춥니다.

 

* "DOMContentLoaded"/ 다른 스크립트들과 async는 서로를 기다려주지 않습니다.

먼저 다운로드가 끝나는 순서대로 실행합니다.

따라서 async속성의 스크립트가 여러 개 있는 경우, 실행 순서는 제각각입니다.

 

* 동적 스크립트

let script = document.createElement('script');
script.src = "./script.js";
document.body.append(script);

위와 같이 동적으로 스크립트를 추가한다면 기본적으로 async 스크립트처럼 행동합니다.

 

 

 

 

 

 

 

이 사진을 보시면 이해하기 쉽습니다.

 

 

참고 : https://ko.javascript.info/script-async-defer