[WEB] 스크립트의 로드 시점 - async & defer

📙 브라우저가 HTML을 해석(Parsing)할 때 어떤일이 일어나는가 ?

스크립트의 로드 시점을 알기전에 브라우저가HTML문서를 해석(Parsing)할 때 일어나는 일들에 대해서 이해하면 좋을것 같다.

  1. 불러오기 및 데이터 파싱
    HTTP 모듈 또는 파일시스템으로 전달받은 리소스 스트림(resource stream)을 읽는 과정을 거치고 파싱을 통해 DOM(Document Object Model)트리를 생성한다.
  2. CSS 스타일 결졍
    문서의 요소를 어떻게 보여줄 것인지 결정하는 요소를 파싱한다.
  3. 렌더링 트리 만들기
    파싱으로 DOM 트리가 생성되는 동안 렌더링 트리를 만든다. 표시해야할 순서와 문서의 시각적인 요소로써 올바른 순서로 내용을 그리기 위해 별도의 트리구조가 필요한데 이를 렌더링 트리라고 부른다.
  4. 레이아웃
    렌더링 트리가 생성될 때, 각 랜더링 객체가 위치와 크기를 갖게되는 과정을 레이아웃이라고 한다.
  5. 그리기
    그리기 단계에서는 렌더링 트리를 탐색하면서 특정 메모리 공간에 RGB값을 체우는 과정이다.

파싱(Parsing )?

문서를 파싱한다는 것은 문서에서 읽어낸 데이터를 이해하고 사용할 수 있는 형태로 변환하는 것을 의미한다. 이러한 동작을 하는 기능또는 프로그램을 파서(Parser) 라고 한다.
브라우저에서 HTML 문서를 파싱한 결과를 파싱트리(parse tree) 또는 문법트리(syntax tree)라고 부른다.

📕 일반적인 스크립트의 로드

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
    <link rel="stylesheet" type="text/css" href="default.css" />
    <link rel="stylesheet" type="text/css" href="dark.css" />
    <script src="jquery.js"></script>
    <script src="main.js"></script>
  </head>
  <body>
    ...
  </body>
</html>

위와 같은 문서를 불러올 때 브라우저는 먼저 HTML을 파싱하고 외부자원인 CSS, JS 파일을 로드하게 된다.
DOM 트리가 완성되면 이미지 파일이나 외부 리소스를 로드하면서 모든 작업이 완료된다.

여기서 중요한 점은 브라우저가 script를 해석할 때 어떻게 되는 것인가 인데, 일반적인 경우에는 자바스크립트는 인라인 코드의 경우 즉시 실행되고 파일로 전달했을 때는 전달이 완료된 시점에 실행된다. 문제는 아래의 그림과 같이 브라우저가 자바스크립트 다운로드 및 실행하는 동안은 문서의 파싱은 중단된다.

한편 CSS는 DOM트리를 변경하지 않기 때문에 문서파싱을 기다리거나 중단하지 않는다.
위의 코드에서는 스타일을 먼저 불러온 뒤 스크립트를 로드하지만 만약 스크립트 파일을 먼저 로드하게 될 경우에 스크립트에서 스타일 정보를 요청하게 된다면 잘못된 결과를 내놓기 때문에 결과적으로 사용자경험(UX)을 떨어뜨리게 될 것이다. 이런 문제는 흔치않은 것처럼 보이지만 매우 빈번하게 발생한다.

따라서 위 코드를 다음과 같이 스크립트 태그를 body 태그 끝에 두는것을 권장한다.

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
    <link rel="stylesheet" type="text/css" href="default.css" />
    <link rel="stylesheet" type="text/css" href="dark.css" />
  </head>
  <body>
    ...
    <script src="jquery.js"></script>
    <script src="main.js"></script>
  </body>
</html>

📘 스크립트 로드 방식 async, defer

async 속성을 사용할 때

async 속성을 사용하여 스크립트 파일이 비동기적으로 실행될 수 있음을 나타낼때 사용할 수 있다. 즉, 브라우저가 async 속성이 있는 스크립트 태그를 만났을 때 HTML 파싱을 멈추지 않고 스크립트가 실행할 준비가 되었을 때 실행시킨다.

<script async src="main.js"></script>

스크립트의 실행순서가 다운로드 완료된 시점에서 결정이 되므로 실행 순서가 중요한 스크립트들에 async 속성을 사용할 때는 유의해야한다.

defer 속성을 사용할 때

defer 속성은 HTML 파싱이 종료되었을 때 스크립트 파일을 실행하도록 브라우저에게 지시하게 된다.

<script defer src="main.js"></script>

위 그림과 같이 브라우저가 스크립트를 다운로드를 완료하더라도 스크립트는 바로 실행되지 않는다. 또한 async와 다른점은 호출된 순서대로 실행이 된다는 점이다.

언제 사용하면 좋을까 ?

스크립트의 의존성 여부에 따라 결정하면 유용하게 사용할 수 있을 것이다. 의존성이 없는 스크립트의 파일을 실행할 때는 async를 적절하게 사용하고, 의존성과 실행순서가 중요하다면 defer를 사용해 주면 유용할 것이다.

✏️ 정리

  • 브라우저가 HTML 문서를 파싱할 때 스크립트를 만나게 되면 파싱을 중지한다.
  • 스크립트태그의 async, defer 속성을 적절히 활용하여 스크립트가 실행되어야 할 순서를 제어할 수 있다.

📚 참고링크

네이버 D2 - 브라우저는 어떻게 동작하는가?

좋은 웹페이지 즐겨찾기