안녕하세요. IT 엘도라도 에 오신 것을 환영합니다.
글을 쓰는 것은 귀찮지만 다시 찾아보는 것은 더 귀찮습니다.
완전한 나만의 것으로 만들기 위해 지식을 차곡차곡 저장해 보아요.   포스팅 둘러보기 ▼

자바스크립트 (JavaScript)

[JavaScript] script 태그 옵션 (async, defer)

피그브라더 2022. 10. 7. 14:33

우리는 외부 JavaScript 파일을 로드하여 사용할 때 <script> 태그를 사용한다. 그런데 <script> 태그에는 해당 JavaScript 파일의 로드 및 실행 시점에 영향을 주는 특별한 옵션(어트리뷰트)이 두 가지 있다. 바로 asyncdefer이다. 길게 설명하면 끝도 없지만, 웹 개발자로서 기본적으로 알고 있어야 하는 핵심적인 골자 정도는 이번 기회에 정리하고 넘어가자.

 

1. 기본적인 <script> 태그의 동작

기본적으로 브라우저는 HTML을 파싱하면서 DOM을 생성한다. 그런데 그러는 도중에 <script> 태그를 만나면, 해당 JavaScript 파일을 로드하고 실행을 완료할 때까지 원래 하고 있던 HTML 파싱 및 DOM 생성 작업은 잠시 중단한다. 그림으로 보면 다음과 같다.

 

 

그런데 이와 같은 기본 동작은 다음과 같은 문제점들을 내포하고 있다.

 

  1. JavaScript 파일을 실행하는 시점에 아직 생성되지 못한 DOM에는 접근할 수 없다.
  2. 무거운 JavaScript 파일을 로드 및 실행하는 경우 페이지 렌더링이 눈에 띄게 지연된다.

 

따라서 이와 같은 문제를 해결하려면, <script> 태그를 문서의 최대한 아래쪽에 배치해야 할 것이다. 그러나 이 또한 HTML 문서 자체가 굉장히 무거운 경우에는 해당 JavaScript 파일의 로드 및 실행이 눈에 띄게 지연된다는 문제가 있다. 이러한 문제를 해결하기 위해 등장한 것이 바로 <script> 태그에 지정할 수 있는 async, defer 어트리뷰트이다.

 

2. async 어트리뷰트

<script> 태그에 async 어트리뷰트를 지정하는 경우, 다음과 같은 변화가 생긴다.

 

  1. JavaScript 파일이 백그라운드에서 로드된다. (HTML 파싱 및 DOM 생성 작업을 중단시키지 않는다.)
  2. JavaScript 파일의 로드가 완료되는 순서대로 실행되며, 그때 HMTL 파싱 및 DOM 생성 작업은 중단된다.

 

이를 그림으로 나타내면 다음과 같다.

 

 

위 그림에 두 가지 경우가 표현된 이유는 다음과 같다. DOMContentLoaded는 HTML 파싱 및 DOM 생성 작업이 완료되면 발생하는 이벤트인데, JavaScript 파일의 로드 및 실행이 언제 완료되느냐에 따라 해당 JavaScript 파일의 실행이 DOMContentLoaded 이벤트의 발생 전에 완료될 수도, 발생 후에 완료될 수도 있음을 보여주기 위해서이다. 즉, 다른 스크립트와의 의존성이 전혀 없이 독립적으로 로드 및 실행되는 특징을 지니기 때문에, 방문자 수 측정 등의 마케팅 관련 스크립트에서 주로 사용되는 경향이 있다.

 

한편, 다음과 같이 JavaScript에 의해 동적으로 추가되는 <script> 태그도 기본적으로 async 어트리뷰트가 지정된 것처럼 동작한다. 따라서 로드가 완료되는 순서대로 실행된다. 만약 이러한 동작을 막으려면 명시적으로 async 프로퍼티의 값을 false로 설정해줘야 한다.

function loadScript(src) {
    const script = document.createElement('script');
    
    script.src = src;
    // script.async = false;
 
    // 해당 JavaScript 파일의 로드 및 실행 시작
    document.body.append(script);
}

// 로드가 완료되는 순서대로 실행
loadScript('/it-eldorado/first-script.js');
loadScript('/it-eldorado/second-script.js');

 

3. defer 어트리뷰트

<script> 태그에 defer 어트리뷰트를 지정하는 경우, 다음과 같은 변화가 생긴다.

 

  1. JavaScript 파일이 백그라운드에서 로드된다. (HTML 파싱 및 DOM 생성 작업을 중단시키지 않는다.)
  2. HTML 파싱 및 DOM 생성 작업이 완료된 이후 DOMContentLoaded 이벤트 발생 직전에 HTML에 작성된 순서대로 실행된다.

 

이를 그림으로 나타내면 다음과 같다.

 

 

async 어트리뷰트와 달리, 반드시 DOMContentLoaded 이벤트의 발생 전에 JavaScript 파일이 실행된다는 것을 볼 수 있다. 또한, 로드가 완료되는 시점과 무관하게 HTML에 작성된 순서대로 실행되기 때문에, 다른 스크립트에 대한 의존성이 강하다. 쉽게 말해서, <script> 태그를 작성하는 위치가 중요해진다는 뜻이다.

 

4. 요약

지금까지 설명한 <script> 태그의 동작을 하나의 그림으로 압축하면 다음과 같다.

 

 

 

 

 

 

 

본 글은 아래 링크의 내용을 참고하여 학습한 내용을 나름대로 정리한 글임을 밝힙니다.

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