[Javascript] script async 와 defer의 차이점
브라우저의 동작 방식
모던 웹브라우저에서 돌아가는 스크립트들은 대부분 HTML보다 ‘무겁다’. 용량이 커서 다운로드받는 데 오랜 시간이 걸리고 처리하는 것 역시 마찬가지이다.
사용자가 HTML파일을 다운로드 받았을 때 브라우저는 HTML을 한줄씩 읽으며 CSS와 병합하여 DOM 요소로 변환한다. HTML을 파싱하다가 <script>...</script>
태그를 만나면 HTML 파싱을 잠시 멈추고 스크립트를 먼저 실행해야 하므로 DOM 생성을 멈춘다. <script src="..."></script>
를 만났을 때 외부에서 스크립트를 다운받고 실행한 후에 남은 페이지를 처리한다.
이런 브라우저의 동작 방식은 두 가지 중요한 이슈를 만든다.
-
스크립트에서는 스크립트 아래에 있는 DOM 요소에 접근할 수 없어 DOM 요소에 핸들러를 추가하는 등의 행위는 불가하다.
-
페이지 위쪽에 용량이 큰 스크립트가 있는 경우 스크립트가 페이지를 '막아버린다'. 페이지에 접속하는 사용자들은 스크립트를 다운받고 실행할 때까지 스크립트 아래쪽 페이지를 볼 수 없다.
<p>...스크립트 앞 콘텐츠...</p>
<script src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>
<!-- 스크립트 다운로드 및 실행이 끝나기 전까지 아래 내용이 보이지 않습니다. -->
<p>...스크립트 뒤 콘텐츠...</p>
일반적으로 HTML에서 <script>
태그의 위치를 <head>
태그의 내부에 위치하게 한다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="main.js"></script>
</head>
<body>
<div>내용</div>
</body>
</html>
위의 2번 특징으로 인해 <head>
태그 아래쪽에 위치한 <body>
태그 내부의 요소들은 스크립트를 다운받는 동안 DOM 생성이 중단되기 때문에 페이지 로딩속도가 느리다는 단점이 있다.
그래서 그 다음으로 많이 하는 것이<body>
태그의 내부 최하단에 <script>
를 넣는 것이다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div>내용</div>
<script src="main.js"></script>
</body>
</html>
이 경우는 js를 받기 전에 이미 HTML파싱이 완료되었기 때문에 사용자들에게 페이지 컨텐츠를 보여줄 수 있다는 장점이 있지만, 만약 이 웹사이트가 js에 의존적이라면 사용자가 정상적인 페이지를 보기까지의 서버에서 js를 다운받고 실행하는 시간이 소요된다.
이러한 현상을 해결하기 위한 방법으로 제시되는 <script>
태그의 옵션들이 있다.
async
<head>
태그 내에 <script>
를 작성하되 async
옵션을 주는 것이다.
async
옵션은 boolean타입의 속성값이기 때문에 선언하는 것만으로도 true로 설정된다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script async src="main.js"></script>
</head>
<body>
<div>내용</div>
</body>
</html>
브라우저가 HTML을 다운로드받아서 파싱하다가 <script>
태그의 async
를 만나면,
main.js
파일을 병렬로 다운로드 하자고 명령만 해두고 다시 HTML을 파싱하다가main.js
의 다운로드가 완료되면- 그 때 파싱하는 것을 멈추고
main.js
를 실행하고- 실행이 완료되면 나머지 HTML을 다시 파싱한다.
이 방법을 사용했을 때 <body>
끝에 선언하는 것 보다 HTML을 파싱하는동안 JS를 다운로드 받을 수 있어 다운로드 받는 시간을 절약할 수 있다는 장점이 있다. 하지만 HTML전체가 파싱되기 전에 JS가 실행되기 때문에 JS에서 DOM 요소를 조작하려 했을 때 해당 요소가 아직 정의되지 않은 상태일 수 있다. 또, JS를 실행하는 동안엔 파싱이 중단되어 페이지가 멈출 수 있기 때문에 사용자가 페이지를 보는 데 시간이 걸릴 수 있다.
defer
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script defer src="main.js"></script>
</head>
<body>
<div>내용</div>
</body>
</html>
브라우저가 HTML을 다운로드받아서 파싱하다가 <script>
태그의 defer
를 만나면,
main.js
파일을 병렬로 다운로드 하자고 명령만 해두고 다시 HTML을 끝까지 파싱하다가- 파싱이 끝난 후 사용자에게 페이지를 먼저 보여준 다음에
- 다운로드 되어진
main.js
를 실행한다.
defer
옵션의 장점은 여러가지의 js파일을 다운로드 받아도 파싱 이후에 순서대로 js파일을 실행한다는 것이다.
이러한 옵션의 특징들을 살펴봤을 때 defer
를 사용하는 것이 안정적이고 효율적으로 JS파일을 보여줄 수 있다는 것을 알 수 있다.
Author And Source
이 문제에 관하여([Javascript] script async 와 defer의 차이점), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@sunkim/Javascript-script-async-와-defer의-차이점저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)