Language/Javascript

Javascript - script 로딩 시 async vs defer

둉이 2021. 12. 13. 20:12

HTML 파일에서 외부 js 파일을 가져오는 방법은 다음과 같다.

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

 

그럼 여기서 궁금한 점이 발생한다. script 태그의 위치는 어디에 위치해야 할까?

 

보통 브라우저는 HTML 문서를 파싱할 때, 위에서부터 차례대로 파싱하게 된다.

그렇기 때문에 파싱 과정에서 script 태그를 만나면 해당 js 파일의 다운로드가 완료될 때까지 DOM 생성을 멈춘다.

 

일반적인 HTML 파싱과 script 작동 방식

 

따라서, 스크립트가 페이지 생성을 막아버리므로 사용자는 스크립트를 다운받을 때까지 스크립트의 아래에 위치한 페이지를 볼 수 없게 된다.

 

이러한 이유 때문에 보통 script 태그는 보통 body의 최하단에 위치하는 게 일반적이다. 

 

하지만 script 태그가 맨 아래에 위치하게 된다면, HTML 문서를 다운로드한 후 스크립트를 다운받아 실행하므로 페이지 로딩 시간이 길어지게 된다. (특히 인터넷이 느린 환경에서는 더 체감이 심함)

 

이를 해결하기 위한 방법으로 script 태그의 asyncdefer 속성이 있다.

 

이 둘은 어떻게 사용하고, 또 차이점은 무엇인지 알아보자!

 

async

async 속성을 사용하면 브라우저는 스크립트를 백그라운드에서 다운로드한다. (대충 비동기로 처리한다는 뜻)

async 스크립트를 사용하는 경우, HTML 파싱과 동시에 script를 다운받고 다운로드가 완료되는 즉시 해당 스크립트가 실행된다.

하지만 js 파일을 실행하는 동안에는 HTML 파싱이 멈춘다는 단점이 있다.

 

그렇기 때문에, 만약 스크립트 A가 실행되는 순간에 A에서 접근하는 DOM이 아직 렌더링되지 않았을 경우 오류가 발생할 수 있다.

따라서, async 속성은 DOM을 조작하지 않고 HTML 의존성이 없는 코드에만 사용하는 것이 바람직하다.

 

async script 동작 방식

 

async 속성을 사용하는 경우, 다운로드 순서는 HTML에 정의된 순서대로 이루어진다. 하지만 위에서도 정리했듯이 스크립트 다운로드가 완료되자마자 실행되므로 실행되는 순서는 다운로드가 완료된 순서를 따른다.

 

예를 들어 아래와 같이 2개의 스크립트를 다운로드하는 경우, small → long 순으로 다운로드가 완료된다면 실행 순서도 small → long 순이다.

// long → small 순으로 다운로드, 다운로드 완료순(small → long)으로 실행
<script async src="https://javascript.info/article/script-async-defer/long.js"></script>
<script async src="https://javascript.info/article/script-async-defer/small.js"></script>

 

defer

defer 속성을 사용하면 async속성과 마찬가지로 브라우저는 스크립트를 백그라운드에서 다운로드한다.

마찬가지로 js 파일을 다운로드 하는 도중에도 HTML 파싱이 일어나므로 페이지 생성이 멈추는 현상이 발생하지 않는다.

 

따라서, defer는 async와는 달리 DOM을 조작하거나 HTML 의존성이 있을 때, 혹은 HTML을 모두 파싱한 후에 실행되어야 하는 코드인 경우에 사용할 수 있다.

 

defer 동작 방식

 

async 속성과의 차이점은 다운로드된 js 파일은 DOM 생성이 끝날 때까지 지연되며, 페이지 생성이 완료되면 실행된다.

정확히는 DOMContentLoaded 직후(DOM 생성이 완료된 직후)에 실행된다.

 

defer 속성을 사용하는 경우, HTML 파일에서 import한 순서대로 다운로드가 진행되며, 마찬가지로 실행 순서도 다운로드 순과 동일하다.

(먼저 다운로드된 파일도 나중에 실행될 수도 있다는 점에서 async와 차이)

// long → small 순으로 다운로드, long → small 순으로 실행
<script defer src="https://javascript.info/article/script-async-defer/long.js"></script>
<script defer src="https://javascript.info/article/script-async-defer/small.js"></script>

 

이제 둘의 공통점과 차이점을 복습해 보자.

  async defer
공통점 HTML 파싱 도중에도 스크립트 파일 다운로드
(파싱이 중단되지 않음)
차이점
(스크립트 실행 시점)
다운로드 순서와는 상관 없이 다운로드가 완료된 순으로 실행 HTML 파싱이 완료된 이후에 순서대로 실행
사용 예시 DOM과는 독립적인 코드 실행
실행 순서가 중요하지 않은 경우
DOM을 조작해야 할 때