- Published on
script를 로드하는 세 가지 방법(async, defer)
들어가기 앞서
웹 브라우저의 동작 방식(링크) 포스트의 랜더링 과정에서 보았듯 script 과정을 만나면 DOM 생성 프로세스를 중지하고 js 실행을 수행한다. 일반적으로 html 보다 script의 용량이 크므로 이를 모두 순차적으로 로드 한다면 웹 페이지가 노출 되기까지 상당한 시간 지연이 생길 수 있다. 그리고 아래 케이스 처럼 DOM 접근이 필요한 script가 존재 할 경우 예상치 못한 사이드 이펙트가 발생할 수 있다.
<script>
// `null` 의 `innerHTML` 에 접근할 수 없으므로 에러가 발생합니다.
console.log(document.getElementById('hello').innerHTML);
</script>
<div id="hello">안녕하세요</div>
<script>
// `안녕하세요` 가 출력됩니다.
console.log(document.getElementById('hello').innerHTML);
</script>
script를 로드하기 위해 주로 쓰이는 세 가지 방식을 알아보고 이런 문제점을 방지하기 위한 방법을 학습하자.
script를 로드하는 세 가지 방법
<!-- 1. default -->
<script src="./script.js"></script>
<!-- 2. async 적용 -->
<script src="./script.js" async></script>
<!-- 3. defer 적용 -->
<script src="./script.js" defer></script>
1. default 방식
<!-- 1. default -->
<script src="./script.js"></script>
- 가장 기본적인 방식.
- 일반적으로 html 보다 script의 용량이 크므로 DOM 랜더링에 지연을 줄이고 예상치 못한 사이드 이펙트를 막기 위해 DOM body 마지막에 모아서 주입.
2. async
<!-- 2. async 적용 -->
<script src="./script.js" async></script>
브라우저는 async 속성이 있는 script는 백그라운드에서 다운로드
- 웹 페이지 로드할 때 html 파서가 해당 속성이 설정된 script를 만나더라도 DOM 랜더링을 멈추지 않음.
script 실행 시점 : script 로드가 완료 되자마자 실행
- 다수개의 script 로드시 특정 script가 상위에 선언되었더라도 용량이 적은 script가 먼저 로드 될 경우 선실행 되므로 script 실행 순서를 알 수 없음.
<!-- 다운로드 걸리는 시간: 10s --> <script src="./a.js" async></script> <!-- 다운로드 걸리는 시간: 1s --> <script src="./b.js" async></script> <!-- 다운로드 걸리는 시간: 5s --> <script src="./c.js" async></script> <!-- script 실행 시점: b - a - c -->
3. defer
<!-- 3. defer 적용 -->
<script src="./script.js" defer></script>
- 브라우저는 defer 속성이 있는 script는 백그라운드에서 다운로드
- 웹 페이지 로드할 때 html 파서가 해당 속성이 설정된 script를 만나더라도 DOM 랜더링을 멈추지 않음.
- script 실행 시점 : DOM이 준비된 이후 선언된 순서대로 실행
async vs defer
- 둘 다 백그라운드에서 로드되기 때문에 DOM 랜더링을 멈추지 않음.
- async는 DOM에 직접 접근하지 않고, 실행 순서가 보장되지 않기 때문에 다른 script에 의존적이지 않은 script를 독립적으로 실행할때 효과적.
- ex. google analytics
- defer는 DOM에 접근해야 하거나, 다른 script에 의존적인 script라 실행 순서가 보장 되어야 할 경우 사용하면 효과적.
ref
- docs
- blog