script 태그의 defer
, async
속성에 대해 정리해보고자 한다.
브라우저의 렌더링은 싱글 쓰레드(Single Thread)로 작동하고, 쓰레드는 렌더링과 스크립트 태그 실행 두가지 일을 모두 수행한다. 그래서 HTML문서를 렌더링하는 과정 중, 스크립트 태그를 만나면 화면 렌더링을 중단하고 스크립트 태그를 실행한다. 만약 이 태그가 외부 스크립트라면 네트워크 통신 시간 + 스크립트 실행으로 인해 다시 돌아와 화면을 렌더링 할 때까지 꽤 오랜시간이 걸릴 것이다. 이는 명백히 사용자 경험을 떨어뜨릴 것이다. 이 문제를 해결하기 위해 나온 것이 defer
와 async
이다.
defer
와 async
두 속성 모두 브라우저의 렌더링 과정을 막지 않는다. 그래서 컨텐츠가 오랫동안 나오지 않는 문제는 발생하지 않게 된다. 하지만 둘은 명백한 차이가 있다.
defer
의 실행 시점은 DOMContentLoaded 이벤트가 발생하기 전에 실행된다. 또한, defer
속성이 있는 스크립트가 여러개가 있다면 문서 순서대로 실행하게 된다.
<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>
예를 들면 위 기준으로 long.js
가 실행되고 small.js
가 실행된다. (다운로드 순서 ❌, 실행 시간 ❌)
<p>첫번째 문단</p>
<script>
document.addEventListener('DOMContentLoaded', () => alert("`defer` 스크립트가 실행된 후, DOM이 준비되었습니다!")); // (2)
</script>
<script defer src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>
<p>두번째 문단</p>
위 예는 첫번째 문단 -> script태그 실행 -> 두번째 문단 -> defer
스크립트 실행 -> alert메소드 순으로 실행된다.
defer
와 비슷하게 동작하지만 큰 차이점은 독립적으로 실행된다는 점이다. 다시말해, async
값을 가진 태그는 DOMcontentLoaded
와 다른 async
태그와 관계없이 준비가 된다면 먼저 실행된다.
<p>첫번째 문단</p>
<script>
document.addEventListener('DOMContentLoaded', () => alert("DOM이 준비 되었습니다!"));
</script>
<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>
<p>두번째 문단</p>
위 코드 기준으로 설명하자면, small.js
의 다운로드가 long.js
보다 빠르게 된다면 small.js
가 먼저 실행되고 long.js
가 나중에 실행된다. 또한, DOMContentLoaded
가 small.js
, long.js
보다 빠르게 실행된다.
defer
의 경우 초기 페이지의 렌더링 과정에서 꼭 필요한 처리지만, 무거운 작업일 경우 사용하고, async
는 페이지와 관련없이 독립적인 기능을 하기 위해 사용하는 것이 좋다.(Ex. 광고 클릭 카운트)
참고