브라우저는 어떻게 동작하는가?
우리가 주소창에 naver.com을 입력하고 Enter를 치는 순간 부터 화면에 naver 홈페이지가 보여지는 과정을 알아보려고 한다. 브라우저는 사용자가 선택한 자원을 서버에 요청하고 표시하도록 도와준다. 우리가 선택한 자원은 HTML문서이거나 이미지 파일이거나 또 다른 형태일 수 있다. 자원의 주소는 URI(Uniform Resource Identifier)에 의해 정해진다.
URI(Uniform Resource Identifier) : 자원의 위치와 고유 식별자를 포함함
ex) https://www.naver.com/login/user?id=122 - URL을 포함한 URI
URL(Uniform Resource Locator) : 자원의 위치를 포함함
ex) https://www.naver.com/login - URL
브라우저의 기본구조
브라우저의 구성요소는 위와 같은 구조로 이루어져 있다.
- 사용자 인터페이스 : 주소표시줄, 북마크바 등 요청한 페이지를 제외한 창의 모든 부분이다.
- 브라우저 엔진 : 사용자 인터페이스와 브라우저 엔진 사이의 동작을 제어한다.
- 렌더링 엔진 : HTML과 CSS를 파싱하여 화면에 표시한다.
- 통신 : HTTP요청과 같은 네트워크 호출에 사용된다.
- UI 백엔드 : 창과 같은 기본적인 UI를 그린다.
- 자바스크립트 해석기 : 자바스크립트 코드를 해석하고 실행한다.
- 자료저장소 : 쿠키와 같은 데이터 자료를 저장한다.
렌더링 엔진의 동작과정
Chrome에서는 Webkit이라는 렌더링 엔진이 요청받은 내용을 브라우저 화면에 표시한다. 렌더링 엔진은 HTML 및 XML 문서와 이미지를 표시할 수 있다.
위 그림은 렌더링 엔진의 기본적인 동작 과정이다.
- HTML문서를 파싱한다.
- 콘텐츠 트리 내부에서 태그를 DOM 노드로 변환한다.
- 외부 CSS파일과 함께 포함된 스타일요소도 파싱한다.
- 스타일정보와 HTML 표시 규칙으로 렌더트리라고 부르는 또 다른 트리를 생성한다.
- 자바스크립트 엔진이 DOM API를 이용해 렌더트리를 변경한다.2
- 렌더트리 생성이 끝나면 배치가 시작된다. 각 노드가 정확한 위치에 표시되는 것을 의미한다.
- 렌더트리를 기반으로 HTML요소의 레이아웃 계산, HTML 요소를 페인팅한다.
파싱과 DOM 트리 구축
파싱을 렌더링 엔진에서 중요한 과정이다. 문서파싱은 브라우저가 코드를 이해하고 사용할 수 있는 구조로 변환하는 것을 의미한다.
HTML 파서는 HTML 마크업을 파싱트리로 변환한다. 파싱트리는 DOM요소와 속성 노드의 트리로써 출력트리가 된다. DOM은 마크업과 1:1 관계를 맺고 DOM 트리로 변환된다.
HTML과는 다르게 CSS는 문맥 자유 문법이다. CSS는 스타일시트 객체로 파싱되고 각 객체는 CSS 규칙을 포함한다. CSS 객체 모델이라고 하여 CSSOM(CSS Object Model)이라고 한다.
위에서 파싱과정을 거쳐 만들어진 DOM과 CSSOM의 트리를 결합하여 렌더트리를 구축하게 되는것이다.
리플로우 리페인트
브라우저 렌더링이 반드시 한 번만 실행되는 것은 아니다. 웹 인터렉션으로 인해 리플로우와 리페인트가 일어난다. 이로 인해 렌더링이 반복되는데, 이를 리렌더링이라고 한다.
리플로우(Reflow) : 레이아웃을 반복하여 수행되는 것
리페인트(Repaint) : 페인트 과정을 반복하여 수행하는 것
리렌더링 되는 원인 등은 다음과 같다.
- 자바스크립트에 의한 노드 추가 또는 삭제
- 브라우저 창의 리사이징으로 인한 뷰포트 크기 변경
- HTML요소의 레이아웃에 변경을 발생시키는 스타일 변경
리렌더링은 성능면에서 좋지 않다. 리렌더링 될때마다 파일을 다시 읽어야 하기 때문이다. 따라서 과하게 노드를 제어하는 것을 지양해야 한다.
자바스크립트 파싱과 실행
파싱과 실행에 대해 자세히 살펴보자. DOM은 HTML의 구조 및 정보 뿐만 아니라, DOM API를 제공한다. DOM API는 이미 생성된 HTML요소를 제어할 수 있다. DOM의 각 노드와 상호작용 하기 위한 인터페이스, 또는 HTML을 자바스크립트에서 제어하기 위한 명령들의 집합체이다. 예를 들어, 자바스크립트에서 document.querySelector()등이다.
CSS를 파싱할 때, link나 script를 만나면 DOM생성을 멈추고 렌더링엔진이 자바스크립트 엔진에게 제어권을 넘긴다. 이를 Blocking이라고 한다. 이후 자바스크립트 파싱과 실행이 종료되면, 다시 렌더링엔진으로 넘어가 파싱이 중단된 시점부터 다시 DOM을 생성한다. 동기적으로 이루어지던 파싱이 script 태그를 만나 일시중지된다는 뜻인데, 동기적으로 이루어지는 DOM생성이 script 태그의 위치에 따라 HTML 파싱을 지연시키므로, script 태그의 위치는 DOM생성 지연에서 중요한 의미를 갖는다.
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#333333" />
<title>유정인</title>
///
<script
const apple = document.getElementById('apple');
apple.style.color = 'red';
// Type Error...
</script>
///
</head>
<body>
<div id="root"></div>
</body>
</html>
위 코드에서 script 태그가 body 태그 위에 위치하게 된다면 apple이라는 element가 만들어지지 않았으므로 오류가 발생한다. 그래서 습관적으로 body태그 끝나는 곳에 script를 작성하는 이유가 DOM트리 형성이 동기적으로 이루어지기 때문이다. DOM이 완성된 후 자바스크립트가 DOM을 조작하므로 오류가 발생하지도 않고, HTML블로킹이 일어나지 않아 성능면에서도 상대적으로 유리하다.
브라우저 렌더링 순서 정리
- 사용자가 브라우저로 웹에 접속하면 브라우저가 IP를 파악한다.
- 브라우저가 서버에게 HTTP Request를 보낸다.
- 서버가 브라우저에게 HTTP Response를 보낸다.
- HTML을 파싱하여 DOM Tree를 생성한다.
- DOM + CSSOM 으로 Render Tree를 생성한다.
- Render Tree에 있는 node를 알맞은 위치에 배치한다. (Layout, Reflow)
- Render Tree에 있는 node의 UI를 그린다. (Paint, Repaint)
- Render Tree에 있는 node를 순서대로 구성한다.
- 사용자에게 결과 화면을 출력한다.
참고자료
'TIL' 카테고리의 다른 글
[Web] LocalStorage SessionStorage Cookie (0) | 2023.08.06 |
---|---|
[React] Virtual DOM (0) | 2023.07.27 |
[Network] RESTful API (0) | 2023.07.25 |
[JS] 클래스(Class) (0) | 2023.07.22 |
[JS] 프로토타입(prototype) (0) | 2023.07.20 |