HTML
스크립트 로딩과 파서 진행
스크립트 파일을 백그라운드로 다운로드하는 것과 메인 스레드에서 실행하는 비용은 서로 다른 문제입니다.
이럴 때 필요해요
스크립트 간 실행 순서를 안전하게 지키면서도 초기 화면 렌더링과 사용자 입력 반응이 멈추지 않도록 로딩 전략을 고르기 위해 필요합니다.
어떻게 동작하나요?
HTML 문서 상단에 아무 속성 없는 일반 <script src="...">를 넣으면 브라우저가 화면을 그리다 말고 하얀 화면에서 멈칫하는 현상이 생깁니다. 스크립트 안에 DOM을 읽거나 수정하는 코드가 있을 수 있어서, HTML 파서가 태그를 만나는 즉시 DOM 생성을 멈추고 파일을 내려받아 실행할 때까지 기다리기 때문입니다.
이 병목을 줄이려고 외부 classic 스크립트에는 defer나 async 속성을 붙입니다. 둘 다 HTML 파싱을 멈추지 않고 백그라운드에서 파일을 병렬로 받아 오지만 실행 시점이 다릅니다. defer는 HTML 파싱이 끝난 뒤 DOMContentLoaded 직전에 문서에 적힌 순서대로 실행되어 의존성 있는 스크립트에 안전하고, async는 다운로드가 먼저 끝난 순서대로 즉시 파싱을 멈추고 실행되므로 실행 순서가 상관없는 독립 분석 스크립트에 적합합니다.
현대 웹에서 많이 쓰는 <script type="module">은 별도 속성을 적지 않아도 기본적으로 defer처럼 지연 실행되며, import로 연결된 모듈 그래프를 알아서 불러옵니다. 만약 모듈에 async를 붙이면 의존 그래프 다운로드가 끝나는 즉시 실행됩니다. 다만 어떤 방식으로 파일을 비동기 로드하더라도, 자바스크립트 코드가 실제로 실행되는 순간에는 메인 스레드를 점유하므로 무거운 초기화 코드는 여전히 화면과 입력 반응을 지연시킬 수 있습니다.
코드 예제
동작을 설명하는 읽기 전용 예제입니다.
<script defer src="vendor.js"></script>
<script defer src="app.js"></script>
<script async src="independent-analytics.js"></script>
<script type="module" src="entry.js"></script>app.js가 vendor.js에 의존할 때는 둘 다 defer를 써서 문서 순서대로 파싱 후 실행되게 보장합니다. 순서가 상관없는 독립 분석 스크립트에만 async를 쓰고, ES 모듈(entry.js)은 자체 import로 의존성을 관리합니다.
자주 헷갈리는 포인트
- script의 async 속성을 Web Worker처럼 별도 백그라운드 스레드에서 코드가 실행된다는 뜻으로 오해하면 안 됩니다.
- src가 없는 인라인(inline) 일반 스크립트에 defer를 붙여도 실행이 뒤로 미뤄지지 않습니다.
내 말로 설명해 보기
서로 실행 순서 의존성이 있는 두 외부 스크립트를 HTML 파싱을 막지 않고 DOMContentLoaded 전에 순서대로 실행하려면 어떤 로딩 방식을 골라야 할까요?
함께 읽으면 좋은 개념
관련 면접 질문 2개
HTML 파싱 중에 일반 script 태그를 만나면 왜 화면 렌더링 진행이 지연되나요?
브라우저의 HTML 파서가 defer나 async가 없는 일반 외부 classic script 태그를 만나면, 기본적으로 DOM 트리 구축을 멈추고 스크립트 다운로드와 실행이 끝날 때까지 기다리기 때문입니다. 스크립트 안에 document.write()나 DOM을 직접 읽고 수정하는 코드가 있을 수 있어 파서가 임의로 뒷부분 HTML을 먼저 처리하기 어렵습니다. 게다가 자바스크립트 실행 자체가 메인 스레드를 오래 점유하면 스타일 계산, 레이아웃, 사용자 입력 반응까지 함께 밀리게 됩니다.
꼬리질문과 참고자료 →script 태그의 async, defer와 type="module"은 로딩 및 실행 시점이 어떻게 다른가요?
외부 classic script에서 async와 defer는 둘 다 HTML 파싱을 멈추지 않고 병렬로 다운로드하지만 실행 시점이 다릅니다. async는 다운로드가 끝나는 즉시 파싱을 멈추고 실행되어 문서 순서를 보장하지 않는 반면, defer는 파싱이 끝난 뒤 DOMContentLoaded 전에 문서 순서대로 실행됩니다. type="module" 스크립트는 기본적으로 defer처럼 지연 실행되며 의존 그래프를 함께 불러오고, 여기에 async를 주면 준비되는 즉시 실행됩니다.
꼬리질문과 참고자료 →