Defer란 무엇인가

SeanKim·2023년 12월 2일

이 글은 코드잇 스프린트 부트캠프를 수강하면서 작성된 내용입니다.

  • 4주차 위클리 미션을 진행하면서 생긴 궁금증을 해결한 과정입니다.

멘토님의 코드리뷰를 보던중

defer 속성을 적용해보라는 조언을 받았다.
근데 defer가 뭐임?

브라우저의 작동 원리

우선 브라우저에서의 JS 파일을 읽어들이는 과정부터 이해해보자.

모던 웹브라우저에서 돌아가는 스크립트들은 대부분 HTML보다 ‘무겁습니다’. 용량이 커서 다운로드받는 데 오랜 시간이 걸리고 처리하는 것 역시 마찬가지이죠.
브라우저는 HTML을 읽다가 <script>...</script> 태그를 만나면 스크립트를 먼저 실행해야 하므로 DOM 생성을 멈춥니다. 이는 src 속성이 있는 외부 스크립트 <script src="..."></script>를 만났을 때도 마찬가지입니다. 외부에서 스크립트를 다운받고 실행한 후에야 남은 페이지를 처리할 수 있습니다.

브라우저는 스크립트 태그를 만나면 DOM 생성을 멈추고 스크립트를 우선 실행시키게 된다.

이런 브라우저의 동작 방식은 두 가지 중요한 이슈를 만듭니다.
1. 스크립트에서는 스크립트 아래에 있는 DOM 요소에 접근할 수 없습니다. 따라서 DOM 요소에 핸들러를 추가하는 것과 같은 여러 행위가 불가능해집니다.
2. 페이지 위쪽에 용량이 큰 스크립트가 있는 경우 스크립트가 페이지를 ‘막아버립니다’. 페이지에 접속하는 사용자들은 스크립트를 다운받고 실행할 때까지 스크립트 아래쪽 페이지를 볼 수 없게 됩니다.
출처 : https://ko.javascript.info/script-async-defer

이런 특징으로 인해 만약 스크립트의 내용이 무거우면(동작이 오래걸리면) 스크립트를 처리하느라 DOM 생성이 늦어져 페이지의 로딩이 느려질 수 밖에 없다. 또는 최악의 경우 그냥 스크립트를 계속 실행하고 DOM 생성을 안 할 수도 있다.

<body>
  ... 스크립트 위 콘텐츠들 ...

  <script src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>
</body>

이런 문제 때문에 보통 스크립트 태그를 body의 하단에 위치시키게 된다.
하단에 위치시키게 되면 DOM 생성이 끝나고 스크립트를 읽어들이게 되므로 우선 페이지에 뭔가 보이게는 될 것이다.

그런데 이게 해결한걸까?

만약 HTML 문서가 아주 크다면 브라우저가 HTML문서를 모두 로드하고 스크립트를 다운받게 하면 페이지가 느려질 것이다. 네트워크가 빠른 환경이라면 큰 문제는 되지 않겠지만, 느린 환경이라면 로딩하는데만 한 세월이 걸릴것이다.

이런 문제를 해결하기 위해 script의 속성 defer, async가 제시됐다.

defer란 무엇인가

브라우저는 defer 속성이 있는 스크립트(이하 defer 스크립트 또는 지연 스크립트)를 '백그라운드’에서 다운로드 합니다. 따라서 지연 스크립트를 다운로드 하는 도중에도 HTML 파싱이 멈추지 않습니다. 그리고 defer 스크립트 실행은 페이지 구성이 끝날 때까지 지연 됩니다.
출처 : https://ko.javascript.info/script-async-defer

defer 속성이 붙은 스크립트는 백그라운드에서 다운로드 되며, HTML 파싱과 병행하여 진행된다. 앞서 말했 듯 스크립트를 다운하게 되면 스크립트를 실행하게 되는데, 페이지 구성이 끝날 때 까지 스크립트를 실행하지 않는다.

<p>...스크립트 앞 콘텐츠...</p>

<script defer src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>

<!-- 바로 볼 수 있네요! -->
<p>...스크립트 뒤 콘텐츠...</p>

이런식으로 속성을 적용하지 않았다면 DOM 생성이 멈췄을 상황에서도 바로 아래의 p 태그도 생성하여 페이지를 완벽하게 보이게 한다.

defer 속성은 외부 스크립트에만 유효하기 때문에 src 속성이 없다면 무시된다고 한다.

async란 무엇인가

async 스크립트는 defer 스크립트와 마찬가지로 백그라운드에서 다운로드됩니다. 따라서 HTML 페이지는 async 스크립트 다운이 완료되길 기다리지 않고 페이지 내 콘텐츠를 처리, 출력합니다(하지만 async 스크립트 실행중에는 HTML 파싱이 멈춥니다 – 옮긴이).
출처 : https://ko.javascript.info/script-async-defer#ref-165

asyncdefer와 마찬가지로 백그라운드에서 다운로드 되지만, 완전히 독립적으로 동작하게 된다.

DOMContentLoaded 이벤트와 async 스크립트는 서로를 기다리지 않습니다.

  • 페이지 구성이 끝난 후에 async 스크립트 다운로딩이 끝난 경우, DOMContentLoadedasync 스크립트 실행 전에 발생할 수 있습니다,
  • async 스크립트가 짧아서 페이지 구성이 끝나기 전에 다운로드 되거나 스크립트가 캐싱처리 된 경우, DOMContentLoadedasync 스크립트 실행 후에 발생할 수도 있습니다.

defer는 다운로드가 완료 된 후 HTML 파싱이 끝난 후에야 실행하지만, async는 그냥 순서없이 독립적으로 실행한다.

안좋은거 아님? 왜 씀?

비동기 스크립트는 방문자 수 카운터나 광고 관련 스크립트처럼 각각 독립적인 역할을 하는 서드 파티 스크립트를 현재 개발 중인 스크립트에 통합하려 할 때 아주 유용합니다. async 스크립트는 개발 중인 스크립트에 의존하지 않고, 그 반대도 마찬가지이기 때문입니다.

독립적인 역할을 하는 스크립트를 기존 프로젝트에 통합할 때 유용하다고 한다.

느낀점

멘토님이 defer에 대한 조언을 해주시기 전까진 아예 이런 속성이 있는지도 몰랐다. 그냥 당연히 body 태그의 하단에 위치시켰고, 당연히 이렇게 하는게 정답인 줄 알았다.

앞으로는 개발 할 때 deferasync를 염두에 두고 개발을 해보자.

profile
프론트엔드 공부 중

0개의 댓글