우리는 외부 JavaScript 파일을 로드하여 사용할 때
<script>
태그를 사용한다. 그런데 <script>
태그에는 해당 JavaScript 파일의 로드 및 실행 시점에 영향을 주는 특별한 옵션(어트리뷰트)이 두 가지 있다. 바로 async
와 defer
이다. 길게 설명하면 끝도 없지만, 웹 개발자로서 기본적으로 알고 있어야 하는 핵심적인 골자 정도는 이번 기회에 정리하고 넘어가자.1. 기본적인 <script> 태그의 동작
기본적으로 브라우저는 HTML을 파싱하면서 DOM을 생성한다. 그런데 그러는 도중에
<script>
태그를 만나면, 해당 JavaScript 파일을 로드하고 실행을 완료할 때까지 원래 하고 있던 HTML 파싱 및 DOM 생성 작업은 잠시 중단한다. 그림으로 보면 다음과 같다.그런데 이와 같은 기본 동작은 다음과 같은 문제점들을 내포하고 있다.
- JavaScript 파일을 실행하는 시점에 아직 생성되지 못한 DOM에는 접근할 수 없다.
- 무거운 JavaScript 파일을 로드 및 실행하는 경우 페이지 렌더링이 눈에 띄게 지연된다.
따라서 이와 같은 문제를 해결하려면,
<script>
태그를 문서의 최대한 아래쪽에 배치해야 할 것이다. 그러나 이 또한 HTML 문서 자체가 굉장히 무거운 경우에는 해당 JavaScript 파일의 로드 및 실행이 눈에 띄게 지연된다는 문제가 있다. 이러한 문제를 해결하기 위해 등장한 것이 바로 <script>
태그에 지정할 수 있는 async
, defer
어트리뷰트이다.2. async 어트리뷰트
<script>
태그에 async
어트리뷰트를 지정하는 경우, 다음과 같은 변화가 생긴다.- JavaScript 파일이 백그라운드에서 로드된다. (HTML 파싱 및 DOM 생성 작업을 중단시키지 않는다.)
- JavaScript 파일의 로드가 완료되는 순서대로 실행되며, 그때 HMTL 파싱 및 DOM 생성 작업은 중단된다.
이를 그림으로 나타내면 다음과 같다.
위 그림에 두 가지 경우가 표현된 이유는 다음과 같다.
DOMContentLoaded
는 HTML 파싱 및 DOM 생성 작업이 완료되면 발생하는 이벤트인데, JavaScript 파일의 로드 및 실행이 언제 완료되느냐에 따라 해당 JavaScript 파일의 실행이 DOMContentLoaded
이벤트의 발생 전에 완료될 수도, 발생 후에 완료될 수도 있음을 보여주기 위해서이다. 즉, 다른 스크립트와의 의존성이 전혀 없이 독립적으로 로드 및 실행되는 특징을 지니기 때문에, 방문자 수 측정 등의 마케팅 관련 스크립트에서 주로 사용되는 경향이 있다.한편, 다음과 같이 JavaScript에 의해 동적으로 추가되는
<script>
태그도 기본적으로 async
어트리뷰트가 지정된 것처럼 동작한다. 따라서 로드가 완료되는 순서대로 실행된다. 만약 이러한 동작을 막으려면 명시적으로 async
프로퍼티의 값을 false
로 설정해줘야 한다.3. defer 어트리뷰트
<script>
태그에 defer
어트리뷰트를 지정하는 경우, 다음과 같은 변화가 생긴다.- JavaScript 파일이 백그라운드에서 로드된다. (HTML 파싱 및 DOM 생성 작업을 중단시키지 않는다.)
- HTML 파싱 및 DOM 생성 작업이 완료된 이후 DOMContentLoaded 이벤트 발생 직전에 HTML에 작성된 순서대로 실행된다.
이를 그림으로 나타내면 다음과 같다.
async
어트리뷰트와 달리, 반드시 DOMContentLoaded
이벤트의 발생 전에 JavaScript 파일이 실행된다는 것을 볼 수 있다. 또한, 로드가 완료되는 시점과 무관하게 HTML에 작성된 순서대로 실행되기 때문에, 다른 스크립트에 대한 의존성이 강하다. 쉽게 말해서, <script>
태그를 작성하는 위치가 중요해진다는 뜻이다.4. 요약
지금까지 설명한
<script>
태그의 동작을 하나의 그림으로 압축하면 다음과 같다.본 글은 아래 링크의 내용을 참고하여 학습한 내용을 나름대로 정리한 글임을 밝힙니다.