이번 글은 'Secrets of the JavaScript Ninja'의 'Chapter 2. Building the page at runtime'을 바탕으로 작성하였습니다.
핵심 Keywords
- 웹 애플리케이션 생애주기의 단계
- 웹 페이지를 만들기 위한 HTML code의 절차
- JavaScript code의 실행 순서
- 이벤트를 활용하여 interactive한 page 만들기
- event loop
사전 지식 체크!
- 브라우저는 HTML code가 짜인 대로 page를 생성하는가?
- 웹 애플리케이션은 한 번에 event를 몇 개 처리하는가?
- 브라우저가 event를 처리하기 위해 event queue를 쓰는 이유?
웹 애플리케이션 생애주기
내용을 본격적으로 살펴보기에 앞서 웹 애플리케이션의 대략적인 생애주기부터 살펴보겠다.
위 그림은 특정 URL에 접속했을 시 브라우저가 작동하는 순서를 나타낸 흐름도이다. 간략히 설명하자면
- URL 접속
- 브라우저가 서버에 보낼 요청을 생성
- 서버는 요청을 처리하고 HTML, CSS, JavaScript로 구성된 응답을 생성
- 브라우저가 응답을 받는 순간 웹 애플리케이션이 비로소 시작
위 그림을 바탕으로 웹 애플리케이션의 생애주기는 크게 2단계로 나눌 수 있다.
- Page Building - 위 그림 2 ~ 4 단계
- Event handling - 위 그림 5 ~ 6 단계
HTML 및 JavaScript code 예제
다음 HTML 및 JavaScript code를 살펴보면서 생애주기가 어떻게 흘러가는지 자세히 살펴보자.
<!DOCTYPE html>
<html lang="en">
<head>
<style>
#first {
color: green;
}
#second {
color: red;
}
</style>
<title>the lifecycle of a web application</title>
</head>
<body>
<ul id="first"></ul>
<script>
// Defines a function that adds a message to an element
// Funtion code is the code contained in a function
function addMessage(element, message) {
const messageElement = document.createElement('li');
messageElement.textContent = message;
element.appendChild(messageElement);
}
// Global code is the code ouside functions
const first = document.querySelector('#first');
addMessage(first, 'Page loading');
</script>
<ul id="second"></ul>
<script>
// Attaches mousemove event handler to body
document.body.addEventListener('mousemove', () => {
const second = document.querySelector('#second');
addMessage(second, 'Event: mousemove');
});
// Attaches click event handler to body
document.body.addEventListener('click', () => {
const second = document.querySelector('#second');
addMessage(second, 'Event: click');
});
</script>
</body>
</html>
1. page-building 단계
아래 그림을 보면서 page-building의 과정을 살펴보자.
웹 애플리케이션은 서버로부터 받은 응답에 담긴 정보들(HTML, CSS, JavaScript 등)로 먼저 뼈대를 만들고 나서, 이벤트와 상호작용을 하고 유저에게 실질적으로 모습을 드러낸다. 이 page-building 단계의 목표는 다음 두 단계를 거쳐 웹 애플리케이션의 UI를 설정하는 것이다.
- HTML 구문 분석 및 DOM(Document Object Model) 생성
- JavaScript code 실행
1단계는 브라우저가 HTML node를 처리하는 단계이고, 2단계는 HTML code 처리 중에 <script> element와 같이 특수한 HTML element를 맞닥뜨렸을 때 실행되는 단계이다. page-building 단계에서 브라우저는 필요한 만큼 1단계와 2단계를 오가며 작업을 수행한다.
Parsing the HTML and building the DOM
HTML과 DOM의 관계는 밀접하지만 같지는 않다. HTML은 DOM 구조를 만들기 위한 일종의 청사진(blueprint)인데, 브라우저는 이 청사진에 오류가 있을 시 자동으로 이를 수정하여 DOM 구조를 생성한다.
브라우저가 page를 생성하던 와중에 <script> element를 만나게 되면 HTML로부터 DOM 구조를 만들어내던 작업을 중단하고, JavaScript code를 실행한다.
Executing JavaScript code
브라우저가 JavaScript 엔진에 보내는 주요한 global object는 페이지가 포함된 창을 나타내는 window object이다. window object는 다른 모든 global objects, 전역 변수(유저가 지정한 것 포함) 및 브라우저 API에 접속할 수 있는 global object이다. 이 global window object에서 가장 중요한 속성 중 하나는 현재 페이지의 DOM을 나타내는 document이다. JavaScript에서 이 object를 활용하여 기존의 element를 수정하거나 삭제하고, 새로운 element를 추가하거나 생성할 수 있다.
다음 JavaScript code를 살펴보자.
const first = document.getElementById("first");
위 예제 code는 'first'란 ID를 가진 element를 선택하기 위해 document object를 사용했다. 이를 활용해 안의 text를 바꾸거나 attribute를 수정하거나 새로운 children을 추가하거나 DOM에서 삭제하는 등 작업을 자유롭게 할 수 있다.
Different types of JavaScript Code
JavaScript code는 크게 2가지 종류로 나뉜다. 다음 예제 코드를 살펴보자.
<script>
// Defines a function that adds a message to an element
// Funtion code is the code contained in a function
function addMessage(element, message) {
const messageElement = document.createElement('li');
messageElement.textContent = message;
element.appendChild(messageElement);
}
// Global code is the code ouside functions
const first = document.querySelector('#first');
addMessage(first, 'Page loading');
</script>
global code는 <script> element와 마주치면 JavaScript 엔진에 의해 한 줄씩 자동으로 실행된다. 반면 function code는 실행되기 위해 다른 global code나 function, 브라우저에 의해 호출되어야 한다.
Figure 2.7의 <script> elemenet 내 JavaScript code가 실행되면 새로운 <li> element를 생성하고, 생성된 <li> element의 text를 수정한 다음 DOM 구조에 수정된 <li> element를 삽입한다. 하지만 아직 생성되지 않은 element에 대한 작업은 할 수 없다. 예를 들어 ID가 'second'인 <ul> element는 선택도 수정도 불가능하다. 왜냐하면 현재 <script> node보다 뒤에 있어서 아직 이르지 못했기 때문이다. 이 때문에 사람들은 <script> node를 HTML code의 맨 마지막 줄에 입력한다.
JavaScript 엔진이 <script> element의 마지막 줄을 실행하고 나면 브라우저는 JavaScript 실행 모드에서 빠져나와 HTML code에 남아 있던 DOM node를 다시 생성하기 시작한다. 이 작업 도중에 또 다른 <script> element를 만나게 된다면 브라우저는 HTML code 작업을 멈추고 <script> element 내의 JavaScript code를 다시 실행한다. 중요한 점은 JavaScript의 global state는 여전히 존재한다는 점이다. 즉 이전 <script> element에서 생성했던 사용자 지정 전역 변수들도 다른 <script> element에서 써먹을 수 있다는 말이다. 이는 global window object에 JavaScript의 모든 전역 변수가 담겨 page의 생애주기 동안 접근 가능하기 때문이다.
page-building과 JavaScript 실행 과정은 처리할 HTML element와 JavaScript code가 있는 한 계속된다.
함께 보기
- HTML Standard
- MDN Web Docs_HTML
https://developer.mozilla.org/en-US/docs/Glossary/HTML5
- DOM Standard
- MDN Web Docs_DOM
https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model
- MDN Web Docs_Web APIs
https://developer.mozilla.org/en-US/docs/Web/API
댓글