코딩을 하다 보면 가끔 스크립트가 제대로 작동하지 않는데
여러 이유가 있겠지만 그중 하나는
페이지가 로드되기 전에 스크립트가 실행되는 이유가 있다.
이러한 점을 방지하기 위한 방법은 여러 가지가 있는데
스크립트를 </body> 바로 위에 로드해서 마지막에 실행되게 하는 방법,
onload, jquery.ready, DOMContentLoaded를 사용해 특정한 콘텐츠가 로드된 후 실행되도록 하는 방법 등 여러 가지가 있다!
오늘은 여러 방법들 중 window.onload, jQuery.ready, DOMContentLoaded의 차이점을 알아보고 무엇을 써야 할지 알아볼 것이다!
우리는 항상 시간이 없다..
바로 본론으로 들어가자!!
DOMContentLoaded
브라우저가 HTML을 전부 읽고 DOM 트리를 완성하는 즉시 발생!
이미지 파일이나 스타일시트 등의 기타 자원은 기다리지 않아!
또, DOMContentLoaded 이벤트는 document 객체에서 발생하기 때문에
이 이벤트를 다루려면 addEventListener를 사용해야 해 !
window.addEventListener('DOMContentLoaded', function() {
//실행 코드
})
예시
<script>
function ready() {
alert('DOM이 준비되었습니다!');
// 이미지가 로드되지 않은 상태이기 때문에 사이즈는 0x0입니다.
alert(`이미지 사이즈: ${img.offsetWidth}x${img.offsetHeight}`);
}
document.addEventListener("DOMContentLoaded", ready);
</script>
<img id="img" src="https://en.js.cx/clipart/train.gif?speed=1&cache=0">
예시 코드를 보면
DOMContentLoaded 핸들러는 문서가 로드되었을 때 실행 돼
따라서 핸들러 아래쪽에 위치한 img태그 뿐만 아니라 모든 요소에 접근 할 수 있어!
하지만 이미지가 로드되는 것을 기다리지 않기 때문에 alert 창엔 이미지 사이즈가 0이라고 뜨지!
처음 DOMContentLoaded 이벤트를 접하면
"DOM 트리가 완성되면 DOMContentLoaded 이벤트가 발생한다"라고 생각하기 때문에
그다지 복잡하지 않은 이벤트라는 생각이 들지!
하지만 DOMContentLoaded에는 몇가지 특이사항이 있어!
DOMContentLoaded와 script
브라우저는 HTML 문서를 처리하는 도중에 <script>태그를 만나면, DOM 트리 구성을 멈추고 <script>를 실행 해!
스크립트실행이 끝난 후에야 나머지 HTML 문서를 처리하지.
<script>에 있는 스크립트가 DOM 조작 관련 로직을 담고 있을 수 있기 때문에 이런 방지책이 만들어진거야!! 신기방기!
따라서, DOMContentLoaded 이벤트 역시 <script> 안에 있는 스크립트가 처리되고 난 후에 발생하지!!
예시 보자보자(넌 담에 보자! 보자보자 아 미안!)
<script>
document.addEventListener("DOMContentLoaded", () => {
alert("DOM이 준비되었습니다!");
});
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js"></script>
<script>
alert("라이브러리 로딩이 끝나고 인라인 스크립트가 실행되었습니다.");
</script>
예시를 실행하면 "라이브러리 로딩이 끝나고..."가 먼저 보인 후 "DOM이 준비되었습니다!"가 출력되지?
스크립트가 모두 실행되고 난 후에 DOMContentLoaded 이벤트가 발생하는거야!!
※ 참고!
DOMContentLoaded를 막지 않는 스크립트
위와 같은 규칙엔 두 가지 예외사항이 있업!
- async 속성이 있는 스크립트는 DOMContentLoaded를 막지 않는다!
- document.createElement('script')로 동적으로 생성되고 웹페이지에 추가된 스크립트는 DOMContentLoaded를 막지 않는다!
DOMCotentLoaded와 styles
외부 스타일시트는 DOM에 영향을 주지 않기 때문에!
DOMContentLoaded는 외부 스타일시트가 로드되기를 기다리지 않아!!
근데 한가지 예외가 있어..
스타일시트를 불러오는 태그 바로 다음에 스크립트가 위치하면
이 스크립트는 스타일시트가 로드되기 전까지 실행되지 않아!!
아래 예시를 보자
<link type="text/css" rel="stylesheet" href="style.css">
<script>
// 이 스크립트는 위 스타일시트가 로드될 때까지 실행되지 않습니다.
alert(getComputedStyle(document.body).marginTop);
</script>
이런 예외는 스크립트에서 스타일에 영향을 받는 요소의 프로퍼티를 사용할 가능성이 있기 때문에 만들어졌어!
예시를 보면 스크립트에서 요소의 좌표 정보를 사용하고 있어.
스타일이 로드되고, 적용되고 난 다음에야 좌표 정보가 확정되기 때문에 자연스레 이런 제약이 생겼어!
DOMContentLoaded는 스크립트가 로드되길 기다려.
예시의 경우라면 당연히 스타일시트 역시 기다리게 되지!
브라우저 내장 자동완성
Firefox와 Chrome, Opera의 폼 자동완성(form autofill)은 DOMContentLoaded에서 일어나!!
페이지에 아이디와 비밀번호를 적는 폼이 있고, 브라우저에 아이디, 비밀번호 정보가 저장되어 있다면 DOMContentLoaded 이벤트가 발생할 때 인증 정보가 자동으로 채워져
물론 사용자가 자동 완성을 허용했을 때 그렇겠지!
따라서 실행해야 할 스크립트가 길어서 DOMContentLoaded 이벤트가 지연된다면 자동완성 역시 뒤늦게 처리 돼!
브라우저 자동 완성 기능을 켜 놓은 사용자라면 특정 사이트에서 자동 완성이 늦게 처리되는 걸 경험 해봤을 거야!
이런 사이트에선 페이지 로딩이 다 끝난 후에야 아이디나 패스워드 같은 브라우저에 저장한 정보가 폼에 뜨지!
이런 지연이 발생하는 이유는 DOMContentLoaded 이벤트가 실행되는 시점 때문이야! 너무신기한데..
※ 또 다른 특징으로는 IE8 이하에서는 지원하지 않아!
비슷한 기능을 하는 jQuery의 ready 메소드를 순수 자바스크립트로 대체하는 방법을 탐구하다 발견한 방법(링크)
// Mozilla, Opera, Webkit
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", function () {
document.removeEventListener("DOMContentLoaded", arguments.callee, false);
domReady();
}, false);
}
// Internet Explorer
else if (document.attachEvent) {
document.attachEvent("onreadystatechange", function () {
if (document.readyState === "complete") {
document.detachEvent("onreadystatechange", arguments.callee);
domReady();
}
});
}
//DOM이 모두 로드 되었을 때
function domReady () {
//처리할 내용
}
window.onload
window 객체의 load 이벤트는 스타일, 이미지 등의 리소스들이 모두 로드되었을 때 실행 돼!
load 이벤트는 onload 프로퍼티를 통해서도 사용할 수 있지!
예시를 보자
<script>
window.onload = function() { // window.addEventListener('load', (event) => {와 동일합니다.
alert('페이지 전체가 로드되었습니다.');
// 이번엔 이미지가 제대로 불러와 진 후에 얼럿창이 실행됩니다.
alert(`이미지 사이즈: ${img.offsetWidth}x${img.offsetHeight}`);
};
</script>
<img id="img" src="https://en.js.cx/clipart/train.gif?speed=1&cache=0">
실행해 보면 이미지 사이즈가 제대로 나오지?
window.onload는 이미지가 모두 로드되고 난 후 실행되기 때문에 이미지 사이즈가 제대로 출력되는 거야!
※ 특징
1. 문서에 포함된 모든 콘텐츠가 로드된 후에 실행되기 때문에 불필요한 로딩 시간이 추가될 수 있다!
2. 동일한 문서에 오직 onload는 하나만 실행!
- 중복될 경우, 마지막 선언이 실행!
- 외부 라이브러리에서 이미 선언된 경우 이를 찾아 하나로 합치는 과정이 필요!
3. 외부의 자원(iframe, image, script)을 사용하는 경우에도 해당!
※ <body> 요소에 속성(attribute)으로 지정될 수 있다!
<body onload="실행될 코드">
위와 같이 사용된 경우, window.onload로 지정된 것은 무시된다!
※ window 객체뿐만 아니라 원하는 객체(object)가 로드되었을 때 실행될 코드를 설정할 수 있다!
document.getElmentById("myFrame").onload = function() {
//실행 코드
}
※ 이벤트를 직접 연결할 수 있다!
window.addEventListener('load', function() {
//실행 코드
})
※ jQuery에서는 onload와 같은 동작을 하는 load 메소드를 제공한다.
$(window).load(function() {
//실행 코드
})
jQuery ready
JS의 DOM 트리가 준비되었을 때의 시점을 컨트롤 하는 메소드 (DOMContentLoaded의 jQuery 버전이라 생각!)
$(document).ready(function() {
// 실행 코드
})
※ 특징
1. onload 이벤트보다 먼저 발생한다. 즉, 문서의 모든 자원이 다운로드 되었을 때 발생하는 onload와 달리 DOM 트리만 완성되면 바로 발생하므로 빠른 실행속도가 필요할 때 적합하다.
2. 여러번 사용되면 선언 순서에 따라 순차적으로 실행된다.
결과!
$(document).ready(function() {
alert('document ready');
});
window.onload = function() {
alert('window.onload');
}
window.addEventListener('DOMContentLoaded', function(){
alert('DOMContentLoaded');
});
코드를 실행 런해보면 알겠지만
ready - DOMContentLoaded - onload 순서로 이벤트가 발생한다!
DOMContentLoaded를 사용하지 않는 가장 큰 이유는 ie8 이하에서 지원하지 않기 때문!
ie8 이하를 위한 코드를 작성하면 되지만, 당연히 코드가 길어진다는 단점이 있다.
그래도 원한다면 다음 링크를 참고!! (http://beeker.io/jquery-document-ready-equivalent-vanilla-javascript)
일반적으로 브라우저에서 지원한다고 가정한다면, 아래와 같이 작성할 수 있다.
window.addEventListener('DOMContentLoaded', function () {
// ....
}
관련해서 대중적으로 알려진 다른 의문점들을 확인해보자.
대부분 load 보다 ready 또는 DOMContentLoaded 를 사용하는 이유는 무엇인가?
load 는 모든 리소스를 로드해야하기 때문에 DOMContentLoaded 가 먼저 발생된 후 발생한다.
대부분 모든 리소스를 기다릴 필요가 없는 경우가 많기에, 단순히 빠른 실행을 위함!
관련 이벤트를 하단에 작성하는 이유는 무엇인가?
대부분 스크립트를 </body> 위에 작성하거나, 하단에 작성하는 경우가 많다.
HTML 문서를 파싱하는 과정에서 script 태그를 만난다면, DOM 구축 작업이 중단됨!
중단된 후, script 작업을 실행된 후에 다시 작업이 재실행되는 것!
DOMContentLoaded 이벤트가 발생하는 시점이 script 작업 완료 시간만큼 지연된다는 의미
또한 상황에 따라, DOM 구축이 되지 않은 상태에서 DOM 을 가져오기 때문에, 정상적인 동작이 이루어지지 않음!
출처 : https://mygumi.tistory.com/281
출처 : ko.javascript.info/onload-ondomcontentloaded
'Dev > JS' 카테고리의 다른 글
for ...in for ...of 반복문 비교!!! + forEach문 추가! (0) | 2020.12.16 |
---|---|
JavaScript 객체 기본 중의 기본 중의 기본 중의 기본!! (0) | 2020.12.16 |
getElementById ? querySelector ? 뭘 써야 해 .. ? (2) | 2020.12.14 |
innerHTML ? innerText ? 삐--- textContent를 지향하자 (0) | 2020.12.04 |
브라우저가 지원하지 않아서 ES6를 안쓴다? 핑계 노노해! 바벨(BABEL) (0) | 2020.11.26 |