본문 바로가기

JavaScript

[JavaScript] defer, async 스크립트

 

보통 웹 브라우저에서 돌아가는 스크립트들은 HTML 보다 무겁기 때문에 다운로드 받는 데 오랜 시간이 걸린다.

브라우저는 HTML을 읽다가 <script>태그를 만나면 스크립트를 먼저 실행해야 하므로 DOM 생성을 멈추는데, 이것은 src 속성이 있는 외부 스크립트에도 동일하게 적용된다. 

 

<p> hello </p>
<script src="/"></script>
// 스크립트 다운로드 및 실행이 끝나기 전까지 아래 내용이 보이지 않는다.
<p> hello </p>

 

이런식의 코드를 짜게 되면 두가지 이슈가 생기는데

1. 스크립트에서는 스크립트 아래에 있는 DOM요소에 접근할 수 없다. 따라서 DOM 요소에 핸들러를 추가하는 것과 같은 여러행위가 불가능해진다.

2. 페이지 위쪽에 용량이 큰 스크립트가 있는 경우 스크립트가 페이지를 막아버린다. 페이지에 접속하는 사용자들은 스크립트를 다운받고 실행할 때까지 스크립트 아래쪽 페이지를 볼 수 없게 된다.

이런 부작용들을 피할 수 있는 방법으로 스크립트를 페이지 맨 아래 놓는 방법이 있다.

 

<body>
<script src="/"></script>
</body>

 

하지만 이 방법도 완벽한 해결책은 아니다. HTML 문서 자체가 아주 큰 경우, 브라우저가 HTML 문서 전체를 다운로드 한 다음에 스크립트를 다운받게 하면 페이지가 정말 느려진다.

이러한 문제를 해결할 수 있는 방법이 defer와 async이다.

defer

브라우저는 defer 속성이 있는 스크립트를 백그라운드에서 다운로드 한다. 따라서 지연 스크립트를 다운로드 하는 도중에도 HTML파싱이 멈추지 않는다. 그리고 defer 스크립트 실행은 페이지 구성이 끝날 때까지 지연된다.

<p> hello </p>
<script>
  document.addEventListener('DOMContentLoaded', () => alert("hello"));
</script>
<script defer src="/"></script>
// 바로 볼 수 있다.
<p> hello </p>

위쪽 코드와 비슷한 코드이지만 스크립트에 defer만 붙이면 script밑 코드들도 바로 실행이 된다. 지연 스크립트는 페이지 생성을 막지 않고, DOM이 준비된 후에 실행되긴 하지만 DOMContentLoaded 이벤트 발생 전에 실행된다.

async

async 속성이 붙은 스크립트는 페이지와 완전히 독립적으로 동작한다.

async 스크립트는 defer 스크립트와 마찬가지로 백그라운드에서 다운로드 된다. HTML 페이지는 async 스크립트 다운이 완료되길 기다리지 않고 페이지 내 콘텐츠를 처리, 출력한다.(하지만 async 스크립트 실행중에는 HTML 파싱이 멈춘다.)

<p>hi</p>

<script>
  document.addEventListener('DOMContentLoaded', () => alert("hello"));
</script>

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

<p>hi</p>

또 DOM 이벤트와 async 이벤트는 서로를 기다리지 않는다. 페이지 구성이 끝난 후에 async 스크립트 다운로딩이 끝난 경우, DOM이벤트는 async 스크립트 실행 전에 발생할 수 있다.

async 스크립트가 짧아서 페이지 구성이 끝나기 전에 다운로드 되거나 스크립트가 캐싱처리 된 경우, DOM 이벤트는 async 스크립트 실행 후에 발생할 수도 있다. 요약하자면 async 스크립트는 다른 스크립트를 기다리지 않고 다른 스크립트도 async 스크립트를 기다리지 않는다.

위 코드처럼 long.js 스크립트가 코드 상 위에 있지만 small.js 스크립트가 먼저 다운로드 되는 경우 먼저 실행된다.

 

두 스크립트의 공통점은 다운로드 시 페이지 렌더링을 막지 않는다는 공통점이 있다.

차이점은 다음과 같다.

  순서 DOMContentLoaded
async load-first order. 문서 내 순서와 상관없이 먼저 다운로드된 스크립트가먼저 실행됩니다. 비동기 스크립트는 HTML 문서가 완전히 다운로드되지 않은 상태라도 로드 및 실행될 수 있습니다. 스크립트 크기가 작거나 캐싱 처리 되어있을 때 혹은 HTML 문서 길이가 아주 길 때 이런 일이 발생합니다.
defer 문서에 추가된 순 지연 스크립트는 문서 다운로드와 파싱이 완료된 후에, DOMContentLoaded 이벤트 발생 전에 실행됩니다.

밑에 간단한 그림으로도 확인 가능하다.