html 에서 자바스크립트 파일 가져오기
html 파일에 자바스크립트 파일을 넣어 사용해야 하는 경우가 많이 있다. 이 때에는 기본적으로 html 파일에 <script> 태그를 활용한다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="script.js"></script>
<title>JavaScript</title>
</head>
<body>
<button id="btn">버튼</button>
</body>
</html>
위와 같이 script 태그의 src 속성에 사용할 자바스크립트 파일의 경로를 지정해주면 된다. 만약 script.js 파일의 내용을 "console.log('Hello World!')" 라고 해두었다면 브라우저의 콘솔창에서는 다음과 같은 내용이 출력된다.
이는 script.js 를 실행해서 그 안의 코드를 실행해서 얻게되는 결과가 된다.
버튼 클릭 이벤트 추가에서 발생하는 에러
console.log('Hello World!);
let btn = document.querySelector('#btn');
btn.addEventListener('click', function() {
alert('Hello World!!');
});
btn이라는 아이디 값을 가지고 있는 button 태그에 클릭 이벤트 발생 시 Hello World!! 라는 알림창이 출력되는 자바스크립트 코드를 추가해보았다. 하지만 이상태로 실행을 하면 아래와 같은 내용이 출력된다.
html로 작성된 웹문서를 웹 브라우저를 통해 열게 되면 html 태그의 위에서부터 순차적으로 읽어서 실행이 진행된다. 현재의 html 파일의 경우에도 head ~ meta ~ script 순서로 읽다가 script 태그에 경로가 표시된 script.js파일을 읽어들이게 된다. 그렇게 html파일을 읽는 작업을 멈춘 후에 script.js 파일로 이동해서 해당 파일의 내용들을 실행하기 시작하는데 여기서 btn이라는 아이디를 가진 DOM구조를 찾게 되는 것이다. 문제는 아직 btn이라는 아이디를 가진 태그는 생성되기 전에 이 부분을 실행해버렸다는 것이다. 따라서 당연히 btn의 값은 null이 되게 되고, null인 상태의 값에 동작을 추가하려고 하니 에러가 생기는 것이다.
해결 방법 1. load 위치 수정
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JavaScript</title>
</head>
<body>
<button id="btn">버튼</button>
<script src="script.js"></script>
</body>
</html>
위와 같은 문제를 해결하는 방법은 여러가지가 있다. 그 중 첫번째는 script 파일이 실행되는 위치를 수정하는 것이다. 기존의 html 파일에서 <script> 태그는 <button> 태그의 위에 존재했다. 이를 위와 같이 수정하면 btn이라는 id를 가진 DOM이 구성된 후 script.js 파일에서 이를 선택할 수 있게 되어 alert이 정상적으로 동작한다.
해결방법 2. load 이벤트 리스너 등록
// window.onload 사용
console.log('Hello World!');
window.onload = function() {
let btn = document.querySelector('#btn');
btn.addEventListener('click', function() {
alert('Hello World!!');
});
}
// DOMContentLoaded 사용
document.addEventListener('DOMContentLoaded', function() {
let btn = document.querySelector('#btn');
btn.addEventListener('click', function() {
alert('Hello World!!');
});
});
load 이벤트 리스너를 등록하는 방법에는 두가지가 있다. window.onload 를 사용하는 방식은 html 태그들을 파싱해서 DOM을 모두 생성하고, 외부 콘텐츠들(image, script, css, etc)이 모두 로드된 후에 이벤트를 발생한다. 즉, script.js 파일이 실행은 되지만 window.onload가 적용된 부분은 모든 콘텐츠들의 로드가 끝난 후에 실행이 된다는 뜻이 된다. 하지만 이 경우 외부 콘텐츠가 너무 많은 경우 콘텐츠들이 모두 로드되기를 기다렸다가 자바스크립트 코드가 실행이 되는 것이기 때문에 비효율적이다. 이 때 이용하기 좋은 것이 DOMContentLoaded이다. DOMContentLoaded를 사용하면 html 태그들을 파싱해서 DOM을 생성한 후에 이벤트가 발생하는 것이다. window.onload와 DOMContentLoaded가 적용된 코드가 하나의 자바스크립트 파일에 있는 경우 DOMContentLoaded의 내용이 먼저 실행되고 window.onload의 내용이 실행되는 것을 확인할 수 있다.
해결방법 3. defer, async 이용
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- defer 속성 -->
<script src="script.js" defer></script>
<!-- async 속성 -->
<script src="script.js" async></script>
<title>JavaScript</title>
</head>
<body>
<button id="btn">버튼</button>
</body>
</html>
방법1과 2의 경우 공통적으로 html태그들을 읽던 중 script태그를 만나면 읽고있던 html부분을 잠시 멈춘 후 scipt의 내용을 읽고 다시 html 태그로 돌아오는 방식이었다. 하지만 HTML5에서 새롭게 생겨난 defer, async 속성을 이용하면 비동기 방식으로 script 파일을 읽어들일 수 있게 된다. 여기서 비동기란 html 파일을 읽던 중 script 태그를 만나면 html 파일 읽기를 멈추고 script 파일을 읽는 것이 아니라 두 가지 일을 동시에 진행을 하는 것을 의미한다. 즉, script 파일을 읽는 것을 기다렸다가 html 파일을 다시 읽는 것이 아니라 동시에 병렬적으로 진행하는 것이다. defer 속성의 경우 비동기로 html 파싱과 스크립트파일 읽기가 진행되고 html 파싱이 끝나고 나면 스크립트파일의 내용이 실행된다. async 속성의 경우 defer 속성과 조금 차이를 보인다. async 속성의 경우 비동기로 html 파싱과 스크립트 파일 읽기가 진행되는 것은 같지만 html 파싱 중이라도 스크립트 파일의 로드가 마무리되면 html 파싱이 중단되면서 스크립트 파일이 실행된다. 따라서 자바스크립트 파일을 불러오는 부분에서는 defer 속성을 사용하는 것이 더 권장된다.
댓글