일반 script는 HTML parser를 막을 수 있습니다. async와 defer는 script 다운로드를 parsing과 병렬로 진행하게 해 렌더링 지연을 줄이는 속성입니다. async는 다운로드가 끝나는 즉시 실행되기 때문에 실행 순서가 보장되지 않습니다. 독립적인 analytics script처럼 다른 script나 DOM 순서에 의존하지 않는 경우에 어울립니다.
defer는 다운로드는 병렬로 하되 HTML parsing이 끝난 뒤 문서에 나온 순서대로 실행됩니다. DOM을 사용하거나 여러 script의 실행 순서가 중요하면 보통 defer가 더 안전합니다.
꼬리질문
조금 더 깊게 물어본다면
답변 뒤에 이어질 수 있는 질문들을 하나씩 열어볼 수 있어요.
일반 script는 왜 parsing을 막을 수 있나요?
script가 document.write처럼 문서 구조를 바꾸거나 DOM에 접근할 수 있기 때문입니다. 브라우저는 실행 순서와 문서 상태를 보장하기 위해 parser를 멈출 수 있습니다.
그래서 head에 무거운 일반 script를 두면 초기 렌더링이 늦어질 수 있습니다.
async script는 실행 순서가 보장되나요?
보장되지 않습니다. 먼저 다운로드가 끝난 script가 먼저 실행될 수 있습니다. 서로 의존성이 있는 script에는 적합하지 않을 수 있습니다.
독립적으로 동작하는 추적 script나 광고 script에서 자주 사용됩니다.
defer script는 DOMContentLoaded와 어떤 관계가 있나요?
defer script는 HTML parsing이 끝난 뒤 실행되고, 보통 DOMContentLoaded는 defer script 실행 이후 발생합니다. 그래서 defer script 안에서는 DOM 구조를 사용할 수 있습니다.
이 점 때문에 앱 초기화 script에 defer가 자주 어울립니다.
module script는 기본적으로 어떻게 동작하나요?
type="module" script는 기본적으로 defer와 비슷하게 동작합니다. 또한 module scope를 가지고 strict mode로 실행됩니다.
다만 module graph 로딩과 CORS 등 일반 script와 다른 특징도 있습니다.