Defer와 Async JavaScript의 차이점 및 Core Web Vitals에 미치는 영향
최적의 Core Web Vitals 결과를 위해 언제 JavaScript를 async하고 언제 defer해야 하는지 알아보세요

Defer와 Async JavaScript의 차이점 및 Core Web Vitals에 미치는 영향
고객의 Core Web Vitals를 감사할 때마다 페이지 내에서 파서 차단(sync), 비동기(asynchronous) 또는 지연된(deferred) JavaScript 간의 구분이 거의 없는 경우를 자주 발견합니다. 스크립트마다 최적의 타이밍이 다르기 때문에 이는 매우 안타까운 일입니다.
최종 검토: Arjen Karel, 2026년 3월
Table of Contents!
2025년 Web Almanac에 따르면 모바일 페이지의 15%만이 렌더링 차단 리소스 감사를 통과합니다. 중간값(median)의 페이지는 총 630KB가 넘는 22개의 스크립트를 로드하며, 그중 251KB의 JavaScript는 전혀 사용되지 않습니다. 대부분의 사이트가 너무 많은 JavaScript를 잘못된 시점에 로드하고 있습니다.
요약
페이지의 head에 있는 '일반적인' JavaScript는 다운로드 및 실행이 완료될 때까지 브라우저의 HTML 파싱을 차단합니다. Async 스크립트는 백그라운드에서 다운로드되지만 준비되는 즉시 실행되므로 여전히 파싱을 방해할 수 있습니다. Deferred 스크립트는 백그라운드에서 다운로드되고 파싱이 완료될 때까지 기다렸다가 문서 순서대로 실행됩니다.
DOM을 조작하는 모든 작업에는 defer를 사용하세요. 완전히 독립적인 스크립트(분석, 추적 픽셀 등)에는 async를 사용하세요. 페이지 렌더링 전에 반드시 실행되어야 하는 스크립트의 경우에만 둘 다 사용하지 마세요(sync). 확신이 서지 않는다면 defer를 사용하세요.

1. Synchronous JavaScript (sync)
기본적으로 페이지의 head에 있는 스크립트는 동기식(synchronous)입니다. 브라우저가 동기식 스크립트를 만나면 HTML 파싱을 멈추고 스크립트를 다운로드하여 실행한 후에 파싱을 계속합니다. 즉, 모든 동기식 스크립트가 완료될 때까지 화면에 픽셀이 그려지지 않습니다. 용량이 크거나 속도가 느린 스크립트의 경우, 이는 First Contentful Paint에서 눈에 띄는 지연을 유발합니다.
<!DOCTYPE html> <html> <head> <title>Sync JavaScript Example</title> <script src="script1.js"></script> <script src="script2.js"></script> </head> <body> <!-- Page content here --> </body> </html>
브라우저는 script2.js를 시작하기도 전에 script1.js를 다운로드하고 실행해야 합니다. 그동안 아무것도 렌더링되지 않습니다. 2025년 기준 모바일 페이지 중간값의 Total Blocking Time은 이미 거의 2초에 달합니다. head 내의 동기식 스크립트는 이를 더욱 악화시킵니다.
2. Asynchronous JavaScript (async)
async 속성을 추가하면 브라우저는 HTML 파싱을 계속하면서 백그라운드에서 스크립트를 다운로드합니다. 스크립트는 다운로드가 완료되는 즉시 파서의 현재 위치와 상관없이 실행됩니다. 파싱은 스크립트가 실행되는 동안에만 일시 중지됩니다.
<!DOCTYPE html> <html> <head> <title>Async JavaScript Example</title> <script src="script1.js" async></script> <script src="script2.js" async></script> </head> <body> <!-- Page content here --> </body> </html>
Async 스크립트는 실행 순서를 보장하지 않습니다. 어느 스크립트든 먼저 다운로드되는 것이 먼저 실행됩니다. 만약 script2.js가 script1.js에 의존한다면, async는 예측 불가능한 방식으로 페이지를 망가뜨릴 것입니다. 서로 간에, 그리고 DOM과 완전히 독립적인 스크립트에만 async를 사용하세요.
한 가지 주의할 점은 Chrome에서 async 스크립트는 기본적으로 낮은 네트워크 우선순위(Low network priority)를 갖는다는 것입니다. 이는 브라우저가 예상보다 늦게 다운로드를 시작할 수 있음을 의미합니다. async 스크립트를 (파싱을 차단하지 않고) 빠르게 로드해야 한다면 fetchpriority="high"를 추가하세요.
3. Deferred JavaScript (defer)
defer 속성 역시 백그라운드에서 스크립트를 다운로드하지만, HTML 문서가 완전히 파싱될 때까지 실행이 연기됩니다. Deferred 스크립트는 문서 순서대로 실행되며, DOMContentLoaded 이벤트가 발생하기 직전에 실행됩니다.
<!DOCTYPE html> <html> <head> <title>Defer JavaScript Example</title> <script src="script1.js" defer></script> <script src="script2.js" defer></script> </head> <body> <!-- Page content here --> </body> </html>
Defer는 대부분의 스크립트에서 더 안전한 선택입니다. 스크립트가 실행될 때 DOM을 온전히 사용할 수 있고, 실행 순서가 보존되며, 첫 번째 페인트가 차단되지 않습니다. The Telegraph는 모든 스크립트를 지연(defer)시켜 광고 로딩 시간을 4초 개선했습니다.
4. Module scripts
ES 모듈(<script type="module">)을 사용하면 자동으로 defer 동작이 적용됩니다. 모듈 스크립트는 백그라운드에서 다운로드되고, 파싱 후 실행되며 순서를 유지합니다. 이미 기본값이므로 defer를 명시적으로 추가해도 아무런 효과가 없습니다.
파싱이 완료되기를 기다리지 않고 종속성 그래프가 해결되는 즉시 모듈 스크립트를 실행하려면 async를 추가할 수 있습니다.
비교표
| 속성 | 다운로드 시점 | 실행 시점 | 파싱 차단 여부 | 순서 보존 여부 |
|---|---|---|---|---|
none (sync) |
다운로드 중 파싱 차단 | 다운로드 직후 | 예 (다운로드 + 실행) | 예 |
async |
백그라운드에서 진행 | 다운로드 완료 즉시 | 실행 중에만 차단됨 | 아니요 |
defer |
백그라운드에서 진행 | HTML 파싱 후, DOMContentLoaded 이전 | 아니요 | 예 |
type="module" |
백그라운드에서 진행 | HTML 파싱 후 (defer와 동일) | 아니요 | 예 |
자주 묻는 질문
동일한 태그에 async와 defer를 모두 사용하면 어떻게 되나요? Async가 우선합니다. defer 속성은 완전히 무시됩니다. 이 패턴은 IE9를 위한 폴백(fallback)으로 존재했지만, 2026년 현재는 두 가지를 모두 사용할 이유가 없습니다.
인라인 스크립트에서 async와 defer가 작동하나요? 아니요. 기존 인라인 스크립트(src 없음)에서는 두 속성 모두 무시됩니다. 외부 스크립트에서만 작동합니다. 예외적으로 <script type="module">은 인라인인 경우에도 기본적으로 지연(defer) 처리됩니다.
본문(body) 끝에 스크립트를 넣는 것보다 defer가 더 나은가요? 네. <head> 내의 deferred 스크립트는 즉시(HTML 파싱과 병렬로) 다운로드를 시작합니다. 본문 끝에 있는 스크립트는 파서가 해당 위치에 도달할 때까지 다운로드를 시작할 수 없습니다. Defer는 조기 발견과 지연된 실행이라는 두 가지 장점을 모두 제공합니다.
async 및 defer가 Core Web Vitals에 미치는 영향
동기식 스크립트는 완료될 때까지 아무것도 페인트되지 않기 때문에 FCP에 직접적인 악영향을 미칩니다. 또한, 스크립트가 완료될 때까지 LCP 요소가 렌더링될 수 없다면 LCP에도 악영향을 미칩니다.
Async 스크립트는 FCP를 개선하지만(첫 번째 페인트가 다운로드로 인해 차단되지 않음), 사용자 상호작용 중에 실행되어 메인 스레드를 차단할 경우 여전히 INP 문제를 일으킬 수 있습니다.
Defer 스크립트는 초기 렌더링을 전혀 방해하지 않기 때문에 최적의 페인트 지표를 제공합니다. 단점: 페이지가 콘텐츠를 표시하기 위해 JavaScript에 의존하는 경우(단일 페이지 앱), 파싱이 끝난 후 스크립트가 실행될 때까지 콘텐츠가 나타나지 않기 때문에 defer가 실제로 LCP를 지연시킬 수 있습니다.
CoreDash 모니터링 데이터에 따르면, 모든 비필수 스크립트를 sync에서 defer로 변경한 사이트는 FCP가 평균 340ms 향상되었습니다.
한 단계 더 나아가기: 온디맨드(on demand)로 스크립트 로드
Async와 defer는 파서를 차단하지 않음으로써 페이지 속도를 높일 수 있지만, 스크립트를 지연시킨다고 해서 모든 문제가 해결되는 것은 아니라는 점을 유의해야 합니다. 예를 들어, Largest Contentful Paint 요소는 deferred 및 async 스크립트로 인한 네트워크 및 CPU 경쟁에 취약합니다. Interaction to Next Paint 역시 페이지 로드 중 초기에 실행되는 스크립트의 영향을 받습니다. 그렇기 때문에 페이지 성능에 미치는 영향을 보다 잘 제어하려면 가능한 한 필요에 따라 스크립트를 로드해야 합니다. 당사에서 어떻게 온디맨드로 스크립트를 로드하는지 읽어보세요.
모든 JavaScript 로딩 전략에 대한 전체적인 개요는 JavaScript를 지연시키는 16가지 방법을 참조하세요. Lighthouse의 렌더링 차단 리소스 경고를 해결하고 있다면 해당 가이드에서 해결책을 다루고 있습니다. 또한 JavaScript 우선순위 수준으로 로딩을 미세 조정할 수 있으며 head 대 footer에서의 최적의 스크립트 배치를 선택할 수 있습니다.

