defer와 async는 외부 <script>가 HTML 파싱에 상대적으로 언제 다운로드되고 실행되는지를 바꿉니다. 둘 다 파서를 막지 않고 스크립트를 병렬로 다운로드하게 합니다. 차이는 실행 타이밍입니다.
html
<script src="a.js"></script> <!-- 파싱을 막음: 다운로드 + 실행, 그 후에 계속 -->
<script src="a.js" defer></script> <!-- 파싱 계속; DOM 이후, 순서대로 실행 -->
<script src="a.js" async></script> <!-- 파싱 계속; 가능한 한 빨리, 임의 순서로 실행 -->
시각적 타임라인
text
일반: parse──stop──[download+exec]──parse──────── (가장 느림)
async: parse──────────────────exec──parse──────── (도착하는 대로 실행)
defer: parse───────────────────────────parse──exec (파싱 후, DOMContentLoaded 전)
핵심 차이
async | defer | |
|---|---|---|
| 다운로드 | 병렬 | 병렬 |
| 실행 | 다운로드되는 즉시 | HTML 파싱 완료 후 |
| 순서 유지? | 아니오 (먼저 끝나는 것부터) | 예 (문서 순서) |
| 파서 차단? | 실행 중 잠깐만 | 결코 안 함 |
언제 어느 것을 쓰는가
defer— DOM을 다루거나 서로/순서에 의존하는 스크립트(여러분의 앱 코드)에 사용합니다. DOM이 존재한 후, 순서대로,DOMContentLoaded직전에 실행됩니다.async— DOM이나 다른 스크립트에 의존하지 않는 독립적인 서드파티 스크립트(분석, 광고)에 사용합니다. 순서가 중요하지 않으니 가능한 한 빨리 실행합니다.
html
<script src="analytics.js" async></script> <!-- 독립적 → async -->
<script src="app.js" defer></script> <!-- 앱 로직, 순서 있음 → defer -->
참고: 둘 다 외부 스크립트(src)에만 적용됩니다. 인라인 스크립트에서는 무시됩니다. ES 모듈(type="module")은 기본적으로 defer됩니다.
왜 중요한가
defer/async를 사용하면 스크립트가 HTML 파싱을 막지 않게 되어, 로드 성능과 First Contentful Paint가 직접 개선됩니다.
올바른 것을 고르면(순서가 있고 DOM에 의존하는 앱 코드는 defer, 발사 후 잊는 서드파티 스크립트는 async) 느린 로드와 순서 의존 버그를 모두 피할 수 있습니다.
