Skip to content

Instantly share code, notes, and snippets.

@seia-soto
Forked from jakub-g/async-defer-module.md
Last active May 23, 2023 13:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seia-soto/6a1fb7b0b5ae04bf4471763265ab7786 to your computer and use it in GitHub Desktop.
Save seia-soto/6a1fb7b0b5ae04bf4471763265ab7786 to your computer and use it in GitHub Desktop.
[번역] 비동기 스크립트, 지연 스크립트, 그리고 모듈 스크립트: 설명과 비교 그리고 결론

<script> async, defer, async defer, module, nomodule, src, inline - the cheat sheet

ES modules의 추가와 함께 이제 JS 코드를 로드하기 위한 24가지 이상의 방법이 생겼습니다: (inline|not inline) x (defer|no defer) x (async|no async) x (type=text/javascript | type=module | nomodule) -- 그리고 이들은 미묘하게 다릅니다.

이 문서에서는 속성 값들에 따라 HTML의 <script> 태그가 처리되는 여러가지 방법을 비교했습니다.

만약 <script async type="module"> 혹은 <script nomodule defer src="...">을 언제 써야 할지 궁금해하셨다면 잘 오셨습니다!

Note 이 문서는 <script> 태그들이 HTML에 추가되었을 때를 다룹니다; 런타임에 추가되는 <script> 태그들의 동작은 사뭇 다르니 Jake Archibald (2013)님의 Deep dive into the murky waters of script loading를 참고해주세요.

시각적 표현

그림 하나가 천 마디보다 가치있기 때문에 좋은 시작점으로서 이 섹션이 존재합니다: (credit: https://developers.google.com/web/fundamentals/primers/modules#module-vs-script) 이미지

위 그림에서 볼 수 있듯, async는 부분적으로 꽤 이상할 수도 있습니다: 오래된 스크립트에서 당신은 주로 일들이 나중에 일어나게 하기 위해 사용했고 모듈로써는 더 빨리 일이 일어나게 하기 위해 사용하곤 했습니다 (기본적으로 모듈 스크립트는 지연되어 시작되기 때문입니다).

표준 vs async vs defer vs async defer

defer는 좀 오래되었고, async는 비교적 최신의 것입니다. 그리고 둘 다 잘 지원됩니다.

asyncdefer 간의 직관적인 차이는 async는 더 빠르게 실행하고자 하는 것입니다. (이들은 HTML이 모두 파싱되고 형태를 갖출 때까지는 물론 다른 스크립트들이 모두 다운로드되기까지 기다리지 않아도 됩니다)

  • 모듈이 아닌 "표준" <script> (type=text/javascript 내포, async 사용 안 함, defer 사용 안 함)

    • HTML 파서를 지연시킵니다
    • ℹ️ HTML의 다른 <script>들 전에, 즉시 다운로드되며, 해석되고 실행됩니다
    • ✔️ 순서대로 실행됨이 보장됩니다
    • DOMContentLoaded 이벤트를 지연시킵니다
    • ❌ 위와 같이, "유일한 실패 원인"이 될 수 있고 렌더링 병목이 발생하여 다이내믹 웹 앱의 시작을 지연시키므로, 중요하지 않은 코드에는 적합하지 않습니다.
  • defer 스크립트:

    • ℹ️ (모듈이 아닌) 인라인 스크립트에서는, defer는 무시되고 아무 효과를 가지지 않게 됩니다. (이들은 즉시 실행됩니다)
      • 💡 만약 당신이 정말로, 정말로 필요로 하다면, the base64 hack을 사용할 수 있습니다.
    • ℹ️ (모듈) 인라인 스크립트에서는, defer가 (자동으로) 내포되게 됩니다.
    • ✔️ HTML 파서를 지연시키지 않고 다운로드됩니다.
    • ✔️ 여러 defer 스크립트들 간에 상대적 스크립트 실행 순서가 보장됩니다. (만약 모두 src 속성을 가지고 있다면)
    • ℹ️ DOM이 파싱된 후에 실행됩니다. (하지만 DOMContentLoaded 전에요)
    • DOMContentLoaded 이벤트를 지연시킵니다. (스크립트가 async defer가 아닌 이상)
  • async 스크립트:

    • ℹ️ (모듈이 아닌) 인라인 스크립트에서는, async는 무시되고 아무 효과를 가지지 않게 됩니다.
    • ℹ️ (모듈) 인라인 스크립트에서는, async는 지원됩니다. 출처 - 순서없이, 가능한대로 즉시 실행됩니다.
    • ✔️ HTML 파서를 지연시키지 않고 다운로드됩니다.
    • ⚠️ 순서없이 실행됩니다; 가능한대로 바로 실행됩니다
    • ⚠️ async 스크립트들 사이에 상대적 실행 순서는 보장되지 않습니다. (또한 async, type=module 스크립트에도 적용됩니다)
    • ⚠️ HTML 파싱이 끝날 때까지 기다려주지 않습니다; DOM 빌드를 방해할 수 있습니다 (특히 웹 브라우저의 캐시에서 로드되었을 때)
    • ⚠️ load 이벤트를 지연시킵니다. (DOMContentLoaded 이벤트는 아닙니다)
    • ⚠️ IE9-에서는 지원되지 않습니다.
  • async defer 스크립트:

type=module vs non-module (type=text/javascript) vs <script nomodule>

  • type=module 스크립트 - type=text/javascript 스크립트들과의 차이점:

    • ℹ️ defer를 내포합니다.
    • ℹ️ 인라인 스크립트에서도, defer를 내포합니다. (모듈이 아닌 스크립트들과는 다르게요!)
    • ✔️ 그 후, async가 아닌 모듈 스크립트들 사이에 상대적 실행 순서를 보장해줍니다. (인라인과 src 모두)
    • ✔️ 같은 src가 여러번 로드되어도, 한 번만 실행됩니다
    • ℹ️ 다른 모듈 스크립트에 있는 의존성을 정의하기 위해 import를 사용할 수 있습니다. (이것은 왜 모듈이 지연(defer)되는지에 대한 한 가지 이유입니다)
    • ℹ️ CORS 확인 대상입니다. (교차 출처의 모듈들은 Access-Control-Allow-Origin: *가 필요합니다)
    • ✔️ 지원하지 않는 웹 브라우저들에서는 실행되지 않습니다.
      • ⚠️ 그러나 IE11, Firefox 52 ESR 등에 의해 여전히 다운로드되는 것으로 보입니다.
  • <script nomodule>

Inline vs src

  • 인라인 스크립트 (src없이):

    • ℹ️ 모듈이 아닌 인라인 스크립트: asyncdefer는 모두 무시됩니다; 스크립트는 HTML 파서와 DOM을 빌드하는 것을 지연시키고 즉시 실행됩니다
    • ℹ️ 모듈 인라인 스크립트: defer를 내포합니다; async를 지원하며
    • ❌ 웹 브라우저에서 캐싱할 수 없습니다.
  • src 스크립트:

    • ✔️ (올바른 응답 헤더가 주어졌을 때) 웹 브라우저가 캐싱할 수 있고, 이후 페이지 이동에서 네트워크에서 다운로드될 필요없이 계속 재사용될 수 있습니다.

여러가지 종류의 script 활용 예시

종류 사용 예
script src 이후에 실행될 인라인 스크립트에서 필요로 하는 레거시 라이브러리
script src defer 지연된 실행, 순서를 지키는 경우; e.g. 다른 지연된 스크립트에서 필요로하는 라이브러리; 점진적 향상 코드
script src async 지연된 실행, 순서없이 (독립된 스크립트); e.g. 스스로 초기화되는 애널리틱스 라이브러리
script src async defer 위와 같이, 다만 IE9 지원과 함께
script inline 1) 이후에 실행될 코드들 전에 즉시 실행되어야 하는 작은 코드 (인라인 polyfill, 타이머, 서버에서 생성된 설정), 혹은 되는대로 실행되어야 하는 이벤트 리스너를 등록할 때; 2) 캐싱이 불가능한 코드 (동적으로 생성되었거나 자주 바뀌는 것들 등); 3) 경험 상 중요한 작고 나누어 다운로드하는 것이 오래걸리는 코드
script src module 라이브러리 및 앱, 최신 웹 브라우저에 한하여
script src module async 점진적 향상 코드, 최신 웹 브라우저에 한하여
script inline module 작거나 캐싱할 수 없는 코드, 최신 웹 브라우저에 한하여; 아마도 이후에 정의될 동기식의 모듈에서 필요로 할 인라인 설정 파일에 사용
script inline module async 작거나 캐싱할 수 없는 점진적 향상 코드 (독립적 스크립트), 최신 웹 브라우저에 한하여; 잘 캐싱될 수 있는 라이브러리들을 import할 수도 있는
script nomodule ... 최신 웹 브라우저에 ES 모듈을 배포하는 경우, 오래된 웹 브라우저들을 위한 대체 스크립트
script src async defer module nomodule 독자를 위한 연습으로 남겨두어주세요*

더 읽어보기

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment