기본적으로, 자바스크립트는 파서 차단 리소스(parser blocking resource)입니다. 자바스크립트를 사용하면 콘텐츠, 스타일, 사용자와의 상호작용 등 거의 모든 것을 수정할 수 있습니다. 그렇기 때문에 자바스크립트 실행은 DOM 생성을 차단하고 페이지 렌더링을 지연시키게 됩니다.

최적화하기 위해서 자바스크립트를 비동기로 설정하고, Critical Rendering Path에서 불필요한 자바스크립트를 제거해야 합니다.

Critical Rendering Path에서 불필요한 자바스크립트 제거는 코드 최적화에 가깝습니다. 이번 포스트는 브라우저의 도움을 받을 수 있는 비동기 설정 방법에 초점을 두었습니다.

비동기 설정 방법을 이야기하기 전에 비동기 설정을 해야 하는 이유인 자바스크립트의 종속성에 관해 이야기하도록 하겠습니다.

JavaScript 와 HTML의 종속성

자바스크립트는 DOM 노드와 CSS 스타일을 수정할 수 있는 강력한 기능과 유연성을 보여줍니다.

p span { display: none }
<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="style.css" rel="stylesheet">
    <title>Critical Path: Script</title>
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <script>
      const span = document.getElementsByTagName('span')[0];
      span.textContent = 'interactive'; <!-- change DOM text content -->
      span.style.display = 'inline';    <!-- change CSSOM property -->
      <!-- create a new element, style it, and append it to the DOM -->
      const loadTime = document.createElement('div');
      loadTime.textContent = 'You loaded this page on: ' + new Date();
      loadTime.style.color = 'blue';
      document.body.appendChild(loadTime);
    </script>
  </body>
</html>

만약 위의 인라인 <script>가 span 태그 위로 이동하면 span 노드를 찾을 수 없다고 에러가 발생하게 됩니다. (getElementsByTagName(’span’) 는 null 을 반환합니다.) 이 현상은 자바스크립트가 문서에 삽입된 정확한 위치에서 실행된다는 것을 보여줍니다.

HTML 파서는 <script> 태그를 만나면 DOM 생성 프로세스를 중지하고 자바스크립트 엔진에 권한을 넘깁니다. 자바스크립트 엔진의 실행이 완료된 후 브라우저가 중지했던 시점부터 DOM 생성을 다시 시작합니다.

*<script> 태그의 뒷부분에서 정의된 어떠한 태그들도 아직 생성되지 않았기 때문에 노드를 찾을 수 없습니다. 또한, 인라인 <script> 를 실행하면 DOM 생성이 차단되고, 이로 인해 초기 렌더링도 지연됩니다.*

이러한 이유로 인하여 자바스크립트는 화면에 그려지는 태그들이 모두 파싱 된 후인, body 태그를 닫기 직전에 <script> 태그를 선언하는 것이 좋습니다.