먼저 브라우저가 무엇인지부터 알고 가면 좋을 것 같다.
브라우저란?
인터넷을 통해 웹 페이지를 탐색하고 사용할 수 있도록 도와주는 소프트웨어이다.
HTML, CSS, JS를 이용하여 웹 페이지를 해석하고 렌더링한다.
브라우저는 위의 사진과 같이 구성되어 있다.
- 사용자 인터페이스
우리가 사용하는 브라우저의 주소 표시줄, 이전/다음 버튼 등 직접 상호작용하는 부분이다. - 브라우저 엔진
사용자 인터페이스와 렌더링 엔진 사이의 동작을 제어한다.
DOM 자료구조를 구현한다. - 렌더링 엔진
HTML 및 CSS를 해석하여 화면에 출력하는 역할을 한다. - 통신
HTTP 요청과 같은 네트워크 호출에 사용된다. - 자바스크립트 해석기
JS는 한 줄씩 읽어가며 파싱하는 언어이기 때문에 해석기가 필요하다.
자바스크립트 엔진이라고도 불린다. - UI 백엔드
렌더링 엔진이 분석한 렌터 트리를 브라우저에 그리는 역할을 한다. - 자료 저장소
로컬/세션 스토리지 등이 여기에 속한다.
사용자가 URL을 입력하면, 브라우저 엔진은 해당 페이지를 가져오고 렌더링 엔진이 화면에 렌더링하는 것이다.
렌더링 : 서버로부터 HTML, CSS, JS 파일을 받아 브라우저에 시각적으로 출력하는 것
브라우저 렌더링 과정
파싱 : 브라우저가 코드를 이해하고 사용하기 쉬운 구조로 변환하는 것
- HTML 파싱과 DOM 생성
HTML 문서는 텍스트이므로 브라우저가 이해하기 위해서는 번역이 필요하다.
이 때, 렌더링 엔진이 사용되고 렌더링 엔진은 HTML 문서를 파싱하여 DOM 트리를 생성한다.
DOM 트리를 생성하는 방법은 다음과 같다.
- 서버에서 HTML을 바이트 형식으로 응답
- 브라우저는 HTML을 바이트에서 문자열로 바꿈
- 문자열을 토큰으로 분해
- 토큰을 객체로 변환하여 노드들을 생성
- 노드들로 구성된 DOM 생성
- CSS 파싱과 CSSOM 생성
렌더링 엔진은 한 줄 씩 파싱하면서 DOM을 생성한다.
이 때, 중간에 CSS를 불러오는 link나 style 태그를 만나면 DOM 생성을 일시 중단한다.
CSS 파일을 서버에 요청하고 응답 받은 파일을 HTML과 동일하게 파싱해서 CSSOM 트리를 생성한다.
CSS 파싱이 완료되면 중단했던 곳으로 돌아가 다시 HTML을 파싱한다.
- 자바스크립트 파싱과 실행
CSS 파싱과 동일하게 HTML을 파싱하는 도중에 자바스크립트 파일을 로드하는 태그를 만나면 DOM 생성을 일시 중단한다.
자바스크립트 파일을 받아온 후, 자바스크립트 코드를 파싱하기 위해 자바스크립트 엔진에게 제어권을 넘긴다.
자바스크립트 엔진은 코드를 해석하여 추상 구문 Tree인 AST(Abstract Syntax Tree)를 생성한다.
자바스크립트 파싱이 완료되면 중단했던 곳으로 돌아가 다시 HTML을 파싱한다.
- 렌더 트리 생성
생성된 DOM과 CSSOM을 결합하여 렌더 트리를 만든다.
렌더 트리에는 브라우저에 보이지 않는 것들은 포함되지 않는다.(display: none 같은)
렌더 트리는 HTML 요소의 레이아웃(위치, 크기)을 계산하는데 사용되고,
브라우저 화면에 픽셀을 렌더링하는 페인팅 처리에 입력된다.
여기까지의 과정을 Construction이라고 한다.
- 레이아웃
렌더 트리의 노드들을 순회하며 각 요소의 정확한 위치와 크기를 계산한다.
모든 상대적인 값들(%, em)은 화면에서 절대적인 픽셀로 변환된다.
- 페인팅
UI 백엔드가 렌더 트리의 노드들을 돌면서 UI를 그리는 작업이다.
레이아웃 단계에서 계산된 위치와 크기 정보를 바탕으로 실제 화면에 요소들을 그린다.
- Composition
노드들의 레이어를 순서대로 구성한다.
z-index가 낮은 요소를 먼저 놓고 그 다음에 높은 요소를 놓는 것이다.
Layout 작업부터 Composition까지의 과정을 Operation이라고 한다.
최종적으로 사용자에게 결과화면을 보여주게 된다.
렌더링 최적화
- 자바스크립트에 의한 노드 추가 또는 삭제
- 브라우저 창 리사이징에 의한 뷰포트 변경
- HTML 요소의 레이아웃에 변경을 발생시키는 width, height 등의 스타일 변경
위의 경우에 브라우저가 리렌더링 된다.
브라우저에서 리렌더링은 성능에 악영향을 준다.
따라서 리렌더링이 자주 일어나지 않도록 하는게 중요하다.
또한 자바스크립트 파일을 만나면 HTML 파싱이 중단된다.
이는 HTML 파싱이 블로킹되어 DOM 생성이 지연될 수가 있다는 의미이기도 하다.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="style.css">
<script>
const apple = document.getElementById('apple');
$apple.style.color = 'red';
</script>
</head>
<body>
<h2 id="apple"> apple </h2>
</body>
</html>
DOM API를 사용하는 코드가 script 태그 안에 있는데, body 태그보다 위에 위치하는 경우이다.
getElementById('apple') 부분에서 오류가 생긴다.
렌더링 엔진은 위에서부터 한줄씩 읽기 때문에 아직 ID가 apple인 요소가 만들어지지 않았기 때문이다.
따라서 script 태그는 body 요소의 가장 아래 부분에 위치시키는 것이 권장된다.
DOM이 완성된 후에 자바스크립트가 DOM을 조작하기 때문에
요소를 찾지 못하는 오류가 날 가능성도 줄어들고, HTML 블로킹이 없어 페이지 로딩 시간을 단축 시킬 수 있다.
'WEB' 카테고리의 다른 글
Border vs Outline (0) | 2024.07.31 |
---|---|
리플로우와 리페인트(Reflow, Repaint) (0) | 2024.07.08 |
XSS (0) | 2024.07.02 |
CSRF (0) | 2024.07.02 |
HTTP/1.0, HTTP/1.1, HTTP/2, QUIC(HTTP/3) (0) | 2024.06.27 |