반응형

브라우저는 html 파일을 상단 head 태그의 내용부터 순차적으로 파싱을 하게된다.

 

그래서 자바스크립트를 css를 추가하는 것 처럼 head 태그 안에서 사용하게 되면 문제가 발생하게 된다.

<!doctype html>
<html lang="ko">
  <head>
    <script>
      const btn = document.querySelector('#btn');
      btn.addEventListener('click', function(){
        console.log('Hello World');  // undefined btn 에러 출력
      })
    </script>
  </head>
  <body>
    <button id="btn">버튼</button>
  </body>
</html>

 

 

위 소스로 보았을 때 브라우저는 head태그에 있는 script를 먼저 파싱하고

body 태그 안에 있는 DOM 요소를 파싱하기 때문에 

id가 btn인 button 태그를 불러오기 전에 스크립트로 해당 태그를 불러오려고 했으니 undefined 에러가 출력이 된다.

 

위와 같은 이슈를 해결하기 위해서 몇 가지 방법이 있다.

 

1. </body> 태그 상단에 스크립트 작성

보통 스크립트 태그는 </body> 태그 위에 위치해서 사용하는 경우가 많은데

습관적으로 사용해서 의식을 못할 수도 있지만 DOM 파싱 순서 이슈 때문에 사용하게 된다.

<!doctype html>
<html lang="ko">
  <head></head>
  <body>
    <button id="btn">버튼</button>
    
    <script>
      const btn = document.querySelector('#btn');
      btn.addEventListener('click', function(){
        console.log('Hello World');  // 콘솔창에 'Hello World' 정상 출력
      })
    </script>
  </body>
</html>

 

2. load 이벤트 리스너 사용

window.onload나 DOMContentLoaded 이벤트 리스너를 사용해서 HTML이 파싱된 후에 스크립트를 실행할 수 있도록 처리할 수 있다.

  •  window.onload : HTML 파싱으로 DOM 생성, 외부 콘텐츠(이미지, css, script 등) 모든 요소가 로드된 후 발생하는 이벤트
  • DOMContentLoaded : HTML 파싱으로 DOM 생성만 한 후 발생하는 이벤트

 

*window.onload

모든 요소를 다 로드한 후 스크립트를 뿌려주다보니 페이지 내에 요소가 많을 경우 스크립트를 실행하기까지 초기 로딩 시간이 길어질 수 있다.

<!doctype html>
<html lang="ko">
  <head>
    <script>
      window.onload = function(){
        const btn = document.querySelector('#btn');
        btn.addEventListener('click', function(){
          console.log('Hello World');
        })
      }
    </script>
  </head>
  <body>
    <button id="btn">버튼</button>
  </body>
</html>

 

 

* DOMContentLoaded 

HTML DOM만 생성되고 스크립트를 실행하다보니 window.onload 보다 빠르게 실행된다.

<!doctype html>
<html lang="ko">
  <head>
    <script>
      documnet.addEventListener('DOMContentLoaded', function(){
        const btn = document.querySelector('#btn');
        btn.addEventListener('click', function(){
          console.log('Hello World');
        })
      });
    </script>
  </head>
  <body>
    <button id="btn">버튼</button>
  </body>
</html>

 

 

3. defer, async 속성으로 script 로드

HTML5에 추가된 속성으로 script태그에 defer, async 속성을 추가해서 사용한다.

  • defer : HTML 파싱과 함께 비동기로 script를 불러온다.(script 파일은 가져오지만 바로 실행하지 않는다.)
  • async : HTML 파싱과 함께 비동기로 script를 불러온다.(script 파일을 가져오면서 바로 실행한다.)
더보기

*비동기: 브라우저가 HTML 파싱을 하면서 스크립트 태그를 만났을 때하던 작업 (HTML 파싱)을 멈추지 않고 script 파일을 병렬적으로 가져온다.

defer 속성은 HTML을 파싱하면서 script 파일만 불러오고 실행은 나중에 하지만

async 속성은 HTML을 파싱하면서 script 파일을 불러옴과 동시에 실행을 같이 하고 실행하는 순간에는 HTML 파싱을 일시 정지하기 때문에 경우에 따라 에러가 발생할 수 있다.

 

그렇기 때문에 대부분의 경우에는 defer 속성을 사용하고 async는 필요에 따라 사용하면 좋을 것 같다.

 

 

 

 

 

 

 


참고

https://www.youtube.com/watch?v=7qVc4Ez0fnY&list=PLlaP-jSd-nK9LiA2n07uBhzOn9wI53xGV&index=4

 

 

반응형

+ Recent posts