본문 바로가기

HTML

[HTML] Life Cycle(생명 주기) 바로 알기

728x90
반응형

 
 
 
Life Cycle(생명 주기)이란 생애, 그러니까 HTML의 라이프 사이클은 문서(document)가 브라우저상에 생겨나고 변화하고 사라지는 일련의 과정을 뜻한다.
 
HTML 문서의 생명 주기에는 다음의 세 가지 주요 이벤트가 관여한다.
 
 
 

  • DOMContentLoaded

브라우저가 HTML을 전부 읽고 DOM Tree를 완성하는 즉시 발생. 이미지 파일이나 스타일시트 등 기타 자원은 기다리지 않는다.
사용 사례: DOM이 준비된 것을 확인한 후 원하는 DOM 노드를 찾아 핸들러를 등록해 인터페이스를 초기화할 때.
 
 

  • load

DOM Tree 생성이 완성되었을 뿐 아니라 이미지, 스타일시트 등 외부 자원도 모두 불러오는 것이 끝났을 때 발생.
사용 사례: 이미지 사이즈를 확인할 때 등. 외부 자원이 로드된 후 발생하기 때문에 스타일이 적용된 상태이므로 화면에 뿌려지는 요소의 실제 크기를 확인할 수 있음.
 
 

  • beforeunload / unload

사용자가 현재 페이지를 떠나려 할 때 / 떠날 때 발생.
사용 사례:
- beforeunload: 사용자가 사이트를 떠나려 할 때, 변경되지 않은 사항들을 저장했는지 확인시켜 줄 때.
- unload: 사용자가 진짜 떠나기 전에 사용자 분석 정보를 담은 통계 자료를 전송하고자 할 때.
 
 


 
 

DOMContentLoaded

 
DOMContentLoaded 이벤트는 document 객체에서 발생한다. 따라서 이 이벤트를 다루기 위해서는 addEventListener를 사용해야 한다.

// vanilla js 방식
document.addEventListener('DOMContentLoaded', function(){ 
    ... 
 });
// cf) "document.onDOMContentLoaded = ..."는 동작하지 않는다.

// Jquery 방식
$(document).ready(function(){ 
    ...
});

 
 

<script>
document.addEventListener("DOMContentLoaded", () => {
	console.log('DOM이 준비됨');
    
    console.log(`이미지 사이즈: ${img.offsetWidth}x${img.offsetHeight}`);  // "이미지 사이즈: 0 * 0"
});
</script>

<img id="img" src="https://en.js.cx/clipart/train.gif?speed=1&cache=0">


위 예에서 DOMContentLoaded는 DOM Tree가 완성되었을 때 실행된다. 따라서 핸들러 아래쪽에 위치한 <img>와 같은 요소에도 접근할 수 있는 것이다. 하지만 이미지가 로드되기까지는 기다리지 않기 때문에 이미지 사이즈는 0으로 출력된다.
 
이렇게 DOMContentLoaded를 보니 그다지 복잡하진 않은 이벤트라는 생각이 든다. "DOM Tree가 완성되는 즉시 이벤트가 발생한다." 하지만 여기에는 몇 가지 특이사항이 있다.



1) DOMContentLoaded와 script

브라우저는 HTML 문서를 처리하는 도중에 <script>를 만나면 DOM Tree의 생성을 멈추고 <script> 내부의 코드를 실행한다. 그리고 스크립트의 실행이 끝난 후에야 나머지 HTML 문서를 처리한다. <script> 내부의 스크립트가 DOM을 제어하는 로직을 담고 있을 수 있기 때문에 이러한 방지책이 만들어진 것이다. 따라서 DOMContentLoaded 이벤트는 <script> 내부의 스크립트가 처리되고 난 이후에 발생한다.
 

<script>
document.addEventListener("DOMContentLoaded", () => {
  alert("DOM이 준비됨");
});
</script>

<script>
  alert("인라인 스크립트가 실행됨");
</script>

 
위 예시에서는 "인라인 스크립트가 실행됨"이 먼저 보이고 "DOM이 준비됨"이 나중에 출력된다. 스크립트가 모두 실행되고 난 뒤 DOMContentLoaded 이벤트가 발생한 것이다.

자세한 내용은 아래 글 참조.
https://developing-move.tistory.com/224

[WEB] 브라우저 렌더링 과정 바로 알기

브라우저 렌더링의 원리 주소창에 https://www.google.com/을 입력하면 브라우저에서는 무슨 일이 일어날까? 브라우저가 웹 페이지를 불러올 때는 렌더링 엔진이라는 소프트웨어 모듈이 사용된다.

developing-move.tistory.com

 
 
 
 
그러나 위와 같은 규칙에도 두 가지 예외 사항이 있다.
 
DOMContentLoaded를 막지 않는 스크립트
1. async 속성이 있는 스크립트는 DOMContentLoaded를 막지 않는다.
2. document.createElement('script')를 통해 동적으로 웹 페이지에 생성된 스크립트는 DOMContentLoaded를 막지 않는다.
 
 
 

2) DOMContentLoaded와 style
외부 스타일시트는 DOM에 영향을 주지 않기 때문에 DOMContentLoaded는 외부 스타일시트가 로드되기를 기다리지 않는다. 그러나 여기에도 한 가지 예외가 있는데, 스타일시트를 불러오는 태그 바로 다음에 스크립트가 위치하면 이 스크립트는 스타일시트가 로드되기 전까지 실행되지 않는다는 것이다.

<link type="text/css" rel="stylesheet" href="style.css">

<script>
  // 이 스크립트는 위 스타일시트가 로드될 때까지 실행되지 않음.
  console.log(getComputedStyle(document.body).marginTop);
</script>


이러한 예외는 스크립트에서 스타일에 영향을 받는 요소의 프로퍼티를 사용할 가능성이 있기 때문에 만들어졌다(위 예시에서는 marginTop). 스타일시트가 로드되고 적용된 후에야 스타일 정보가 확정되기 때문에 이러한 제약이 생긴 것이다.

DOMContentLoaded는 스크립트가 로드되기를 기다린다. 그러므로 위의 경우라면 당연히 스타일시트의 로드도 기다리게 된다.

 
 
 

3) 브라우저 내장 자동완성
Chrome과 Firefox, Opera의 폼 자동 완성은 DOMContentLoaded에서 일어난다. 따라서 실행해야 할 스크립트가 많아서 DOMContentLoaded가 지연된다면 자동 완성도 뒤늦게 처리된다. 특정 사이트에서 자동 완성이 늦게 처리되는 걸 경험해 보셨다면 DOMContentLoaded 이벤트가 실행되는 시점 때문이었던 것.

 
 


 
 
window.onload


window 객체의 load 이벤트는 스타일, 이미지 등의 리소스들이 모두 로드되었을 때 실행된다. load 이벤트는 onload 프로퍼티를 통해서도 사용할 수 있다.

앞서 DOMContentLoaded 예시와는 달리 아래 예시에서의 onload는 이미지가 모두 로드되고 난 후 실행되기 때문에 이미지 사이즈가 제대로 출력된다.

<script>
window.onload = function() {
  console.log('페이지 전체가 로드됨.');

  console.log(`이미지 사이즈: ${img.offsetWidth}x${img.offsetHeight}`);
};	// window.addEventListener('load', (event) => {...})와 동일함.
</script>

<img id="img" src="https://en.js.cx/clipart/train.gif?speed=1&cache=0">

 
 


 
 

window.onunload
 
unload 이벤트는 사용자가 페이지를 떠날 때, 즉 문서를 완전히 닫을 때 실행된다. unload 이벤트에서는 팝업창을 닫는 것과 같이 딜레이가 없는 작업을 수행할 수 있다. 한편 다른 페이지로 전환 중에 이를 취소하고 싶은 경우가 생길 수 있다. unload에서는 페이지 전환을 취소할 수 없고 onbeforeunload를 사용하면 가능하다.

 

window.onbeforeunload
 
사용자가 현재 페이지를 떠나 다른 페이지로 이동하려고 하거나 창을 닫으려고 할 때 beforeunload 핸들러에서 추가 확인을 요청할 수 있다. 아래 예시에서와 같이 beforeunload 이벤트를 취소하려 하면 브라우저는 사용자에게 확인을 요청한다.
 

// A
window.onbeforeunload = () => {
  return false;
}

// B
window.onbeforeunload = () => {
  return "저장하지 않은 변경 사항이 있습니다. 나가시겠습니까? 정말?";
}


cf) 위 두 코드의 실행 결과로 표출되는 alert창의 메시지는 같다. 오래된 브라우저에서는 문자열을 return하도록 하여 브라우저에 해당 문자열을 보여줬지만, 과거 개발자들의 남용으로 인해 모던 브라우저에서는 onbeforeunload 이벤트를 취소할 때 보이는 메시지는 커스터마이징할 수 없다.

 
 


 
 

readyState

 
간혹 문서가 로드되었는지 아닌지 판단하기 어려운 경우가 있다. DOM이 완전히 구성된 후 특정 함수를 실행해야 하는 경우라면 DOM Tree의 완성 여부를 알 수 없어 난감해진다.
 
이럴 때 현재의 로딩 상태를 알려 주는 document.readyState 프로퍼티를 사용하는 방법이 있다. 이 프로퍼티의 값은 세 종류가 있다.
 
 
loading
  : 문서(document)를 불러오는 중일 때.

interactive
  : 문서가 완전히 불러왔을 때. 문서의 로딩은 끝났지만 image, stylesheet, frame과 같은 하위 자원들은 로딩 중인 상태.
cf) document.readyState는 DOMContentLoaded가 발생하기 직전에 interactive가 됨. 그러나 1ms 이내의 오차 범위 내에서 동시에 실행된 이벤트로 둘은 같은 상태를 나타낸다고 볼 수 있음.

complete
  : 문서를 비롯한 이미지 등 모든 리소스들도 모두 불러왔을 때. load 이벤트가 발생하기 직전의 상태.

cf) document.readyState는 window.onload가 실행되기 바로 직전에 complete가 됨. 그러나 1ms 이내의 오차 범위 내에서 동시에 실행된 이벤트로 둘은 같은 상태를 나타낸다고 볼 수 있음.
 
이제 우리는 document.readyState의 값을 확인하고 상황에 맞게 핸들러를 설정하거나 코드를 실행하면 된다.
 
 
그 외에도 readystatechange 이벤트를 사용하면 변화하는 상태에 맞는 작업을 할 수 있다.
 

// 현재 상태 출력
console.log(document.readyState);

// 상태 변경 출력
document.addEventListener('readystatechange', () => {
	console.log(document.readyState);
})

 
 
 


 
 
이제 아래 예시를 통해 HTML 생명 주기 관련 이벤트와 실행 순서를 예상해 보며 마무리하자.

<script>
  console.log('initial readyState: ' + document.readyState);

  document.addEventListener('readystatechange', () => console.log('readyState: ' + document.readyState));
  document.addEventListener('DOMContentLoaded', () => console.log('DOMContentLoaded'));

  window.onload = () => console.log('window onload');
</script>

<iframe src="iframe.html" onload="console.log('iframe onload')"></iframe>

<img src="http://en.js.cx/clipart/train.gif" id="img">

<script>
  img.onload = () => console.log('img onload');
</script>

 
 
실행 결과
1. initial readyState: loading
2. readyState: interactive
3. DOMContentLoaded
4. iframe onload
5. img onload
6. readyState: complete
7. window onload
 
 
 
 
참고
https://ko.javascript.info/onload-ondomcontentloaded
https://ardor-dev.tistory.com/6
https://lkt01010.tistory.com/215
https://jeong-pro.tistory.com/90
 
 
 
 

728x90
반응형

'HTML' 카테고리의 다른 글

[HTML] 특수기호 - HTML Entities  (0) 2020.08.31
[HTML] 주석  (0) 2020.08.31
[HTML] 전역 속성(7) - tabindex  (0) 2020.08.30
[HTML] 전역 속성(6) - draggable, hidden  (0) 2020.08.30
[HTML] 전역 속성(5) - data  (0) 2020.08.30