
User Interface
: 주소 표시줄, 이전, 이후 버튼, 홈버튼, 북마크 버튼 등 페이지 외의 모든 영역을 의미한다.Browser Engine (Browser Process)
: 사용자 UI와 Rendering Engine 사이의 동작을 제어한다. 주소 표시줄, 이전, 이후 버튼 등 브라우저의 동작 부분을 제어한다. 파일 접근에 필요한 권한 처리 등도 이뤄진.Rendering Engine (Rendering Process)
: 탭 안에서 웹 사이트가 표시되는 영역을 모두 제어한다. 요청한 콘텐츠를 파싱하고 화면에 나타내주는 일을 수행한다.Networking
: HTTP/HTTPS 네트워크 요청이 처리된다.JavaScript Interpreter
: 자바스크립트 코드를 파싱할 때 사용된다.UI Backend
: 기본 위젯을 그릴 때 사용된다. UI Backend는 특정 플랫폼이 아닌 OS의 방법을 사용한다.Date Storage (Data Persistence)
: 쿠키나 localStorage, IndexedDB 같이 로컬에 저장되어 좀 더 오래 유지되어야만 하는 (persistence) 스토리지 메커니즘을 지원하는 영역이다.
모던 브라우저는 대부분 각각의 탭을 독립적인 프로세스로 처리하여 별도의 렌더링 인스턴스를 유지(process per tab)한다. 프로세스를 탭마다 분할함으로써 운영체제가 특정 기능을 제한하여 보안성을 높일 수 있다. 또한 한 탭의 렌더링 프로세스가 응답하지 못할 경우 다른 탭에 영향을 주지 않아 더 좋은 사용성을 제공할 수 있다.
렌더링 과정 살펴보기
사용자가 주소 입력창에 올바른 URL을 입력할 경우 해당 사이트의 화면이 노출된다. 그리고 이 짧은 몇 초 동안 브라우저는 많은 일을 수행한다.
- 사용자가 URL을 입력할 경우 Browser Engine(Browser Process)에서 제일 먼저 작업이 시작된다. Browser Engin(Browser Process)는 브라우저의 UI를 그리는 UI thread, 네트워크 통신을 위한 Network thread, 파일에 접근하기 위한 Storage thread 등이 존재한다.
- 최근에 등장한 브라우저는 대부분 주소창을 자사의 검색창과 동일하게 사용하고 있다. 크롬의 경우 구글, Edge의 경우 bing이 그에 해당한다. 검색창에 입력이 이뤄질 경우 UI thread는 해당 텍스트가 검색어인지 URL인지 확인한다. 검색어일 경우 검색 엔진 URL에 검색어를 결합해 페이지를 이동시키며, URL일 경우 네트워크 호출을 수행한다. 이 때부터 브라우저에는 로딩이 되고 있다는 표시가 나타나게 된다. 동시에 Network thread는 적절한 프로토콜로 요청을 처리하기 시작한다.
- 응답이 도착하기 시작하면 응답이 어떤 타입인지 판단한다. Rendering Process가 다룰 수 있는 HTML이나 PDF(일부 브라우저에 따라 지원하지 않을 수 있다.) 같은 경우 Rendering Process로 전달하며, 다운로드 파일 형식일 경우 다운로드 매니저에게 데이터를 전달해준다. 이 단계에서 해당 사이트가 악성 페이지인지 검사 또한 이루어지며 악성 페이지일 경우 더 이상 처리하지 않고 작업을 중단한다.
- 모든 검사가 끝나면 Network thread는 UI thread에게 작업이 준비되었다고 알려준다. UI thread는 웹 페이지를 렌더링 할 Rendering Engine(Rendering Process)을 찾는다. 네트워크 요청이 오래 걸릴 수 있으므로 URL 요청을 보낼 때 UI thread는 렌더링을 수행할 프로세스를 미리 찾아 바로 사용하는 식으로 최적화가 되어 있기도 한다.
- 데이터와 Rendering Process가 준비되면 본격적으로 페이지의 이동이 시작된다. 이 시점에 Rendering Process는 HTML 데이터를 수신하여 문서를 로딩하며, 브라우저의 주소 표시줄, 사이트 제목 같은 관련 UI들도 갱신된다. 이후에 탭을 이동할 수 있도록 세션 기록이 저장된다.
- 렌더링이 완료되면 Rendering Process는 Browser Process로 로딩이 완료되었음을 알리고 UI thread의 로딩 표시를 중지한다.
Rendering Engine(Rendering Process)의 작업
Rendering Process는 탭 내부에서 발생하는 모든 작업을 담당하며, HTML, CSS, 자바스크립트를 사용자와 상호작용할 수 있는 웹 페이지로 변환한다.
Rendering Process 작업은 위 그림과 같은 단계로 실행되며, 모든 HTML을 파싱할 때까지 기다리지 않고 레이아웃과 페인트를 우선적으로 처리해 내용의 일부를 나타내는 방식으로 수행된다. 이런 점진적인 방식으로 사용성을 높인다.
파싱, Render Tree 생성
파싱(Parsing)은 구문 분석이라고도 불리며, 일련의 문자열을 의미 있는 토큰(token)으로 분해하고 토큰 간의 위계 관계를 분석해 구조를 결정하는 것이다. 파싱 결과는 주로 트리 형태를 나타내는데 이 트리는 parse tree, parsing tree, concrete syntax tree 등으로 불리게 된다. 파서는 이런 과정들을 수행하는 주체이다. HTML과 CSS는 비슷한 과정으로 파싱된다.
과정
- 변환 : 문서를 가져와서 지정된 인코딩 방식으로 읽는다.
- 토큰화 : 표준에 맞춰 지정된 태그들을 토큰화한다.
- 렉싱 (lexical analysis) : 토큰을 해당 속성 및 규칙을 정의하는 노드로 만든다.
- 트리 생성 : root 노드를 기준으로 생성된 노트들의 계층을 연결한다.
HTML 파싱
Rendering Process가 데이터를 수신하기 시작하면 Rendering Process의 메인 thread는 HTML을 파싱해 DOM으로 변환하기 시작한다. 그리고 파싱의 최종 결과로 DOM 트리가 만들어진다. 최상위 노드(root)는 <html>
이다.
웹 사이트는 일반적으로 이미지나 CSS, 자바스크립트 같은 외부 리소스를 필요로 한다. 이런 파일들은 네트워크 혹은 캐시되어 있는 데이터를 통해 가져와야 한다. DOM 트리를 파싱하는 과정에서 데이터를 가져올 수도 있지만, 모던 브라우저에서는 속도를 높이기 위해 <img>
나 <link>
같은 태그가 있으면 미리 Browser Process의 network thread로 요청을 보낸다.
<script>
태그의 경우는 조금 다르다. 자바스크립트에는 문서 전체의 구조를 바꿀 수 있는 (innerHTML
, document.write()
등) 메서드나 프로퍼티가 존재한다. 따라서 문서 중간에 자바스크립트 코드가 있는 경우 이를 로딩하고 파싱하기 위해 브라우저는 HTML 파싱을 중단한다. 그리고 자바스크립트 파싱이 끝난 후 HTML 파싱이 재개된다. 만약 스크립트 파일에서 문서 조작이 이뤄지지 않는다면 <script>
태그에 async나 defer 속성을 지정하여 HTML 파싱을 중단하지 않고 자바스크립트 코드를 비동기적으로 로딩하고 실행할 수 있다.
<!-- 둘 다 백그라운드에서 다운로드된다. 다운로드되는 순서나 DOMContentLoaded와의 관계 등에서는 둘의 동작이 약간 다르다. -->
<script defer src="aaa.js"></script>
<script async src="aaa.js"></script>
CSS 파싱
HTML 파싱 과정에서 <link>
태그를 만나면 해당 CSS 리소스를 가져온다. HTML과 비슷하게 CSS 역시 토큰화, 노드 생성을 거쳐 CSSOM(CSS Object Model)이라는 트리 구조를 가진다. CSSOM은 자바스크립트에서 CSS를 조작할 수 있게 해주는 API 집합이다. DOM이 HTML을 조작할 수 있게 도와준다면, CSSOM은 CSS를 조작할 수 있게 도와준다.
CSSOM 트리의 노드는 DOM 요소의 선택자에 맞춰 적용될 CSS 스타일 정보가 포함되어 있다. <link>
나 <script>
, <title>
, <meta>
같이 화면에 나타나지 않는 요소들에 대한 DOM 요소는 포함되지 않는다. CSS는 부모의 스타일을 상속받는 경우가 존재하기 때문에 CSSOM은 하향식으로 생성된다.
렌더 트리(Render Tree) 만들기
렌더 트리는 CSSOM 트리와 DOM 트리가 결합되어 생성된다. (Gecko 엔진의 경우 렌더 트리를 형상 트리(frame tree)라고 부르며 각 노드를 형상(frame)이라고 부른다. Webkit 엔진은 DOM 트리와 시각 정보를 결합하는 과정을 attachment라고 부른다.)
각 노드는 렌더 객체(Render Object)로 이뤄져 있으며, 렌더 객체는 보이는 노드만을 포함한다.
<html>
태그와<body>
를 처리하며 렌더 트리 루트를 구성한다.- DOM 트리를 순회하며 최상위 노드(
<html>
)부터 보여지지 않는 노드(<link>
,<script>
,<meta>
등)를 생략한다. display: none
처럼 CSS로 숨겨지는 노드 또한 트리에서 생략한다.- float나 position 같은 속성을 사용했을 경우 흐름에서 벗어나 실제 그려지는 위치로 렌더 객체가 이동한다.
- 화면에 나타나는 노드에 CSSOM 규칙을 찾아 일치하는 스타일을 적용한다.
숨겨지는의 의미는 화면에서 해당 노드의 영역을 갖는지를 의미한다.
display: none
과visibility: hidden
은 모두 화면에 해당 요소를 노출하지 않지만,visibility: hidden
은 보이지 않는 상태에도 레이아웃에서 영역을 차지하고 있다. 따라서visibility: hidden
의 스타일을 갖는 노드는 렌더 트리에 포함되며,display: none
의 경우 렌더 트리에 포함되지 않는다.
또한 이후 여러 개의 렌더 객체를 갖는 요소 (select요소는 드롭다운, 버튼 렌더러 객체로 만들어진다.)나 문자가 길어져 한 줄로 표시할 수 없는 경우 새로운 렌더 객체가 생성된다.
레이아웃(Layout)
레이아웃은 각 요소의 상대적인 위치, 크기를 찾는 과정이다. 렌더 트리의 모든 노드들은 자식 노드들의 레이아웃을 호출하는 layout(Gecko 엔진에서는 reflow라고 한다.)을 갖는다. 레이아웃은 렌더 트리의 최상위 노드인 <html>
부터 시작하며 이후 자식 렌더 객체들의 레이아웃을 배치하며 반복적으로 발생한다. 노드의 위치는 (x, y) 좌표계를 사용하며 최상위 노드의 위치는 (0, 0)이다.
레이아웃은 흐름 기반의 배치 모델을 사용한다. 요소가 나타나는 순서대로 ‘왼쪽’에서 ‘오른쪽’으로, ‘위’에서 ‘아래’의 방향으로 진행된다. 일반적으로 ‘이후’의 요소는 ‘이전’의 요소에 영향을 주지 않지만, display: table
이나 display: flex
, display: grid
를 사용할 경우 여러 흐름이 생성되어 영향을 줄 수 있다.
초기 레이아웃 이후 DOM 노드가 추가되거나 변경되었을 경우 변경된 부분을 계산하기 위해 전체 노드를 대상으로 레이아웃이 발생한다면 너무 많은 낭비일 것이다. 레이아웃은 일부의 변경으로 인해 전체를 다시 배치하지 않기 위해 더티 비트(Dirty Bit) 방식을 사용한다. 랜더 객체는 다시 배치할 필요가 있는 변경 요소, 추가된 노드, 그리고 자식 노드를 ‘더티(Dirty)’라고 표시한다.
전체의 레이아웃이 필요한 경우를 글로벌(Global) 레이아웃, 일부만 변경이 이뤄져야 하는 경우를 로컬(Local) 레이아웃이라 부른다. 모든 레이아웃에 영향을 주는 변경이 일어날 경우 글로벌 레이아웃이 일어난다. font-family나 font-size처럼 전역 스타일이 변경되거나 창이 리사이즈되었을 때 발생할 수 있다. 반대로 로컬 레이아웃은 더티 렌더 객체만을 대상으로 한다.
- 부모 노드가 자식 노드의 너비를 결정한다. 너비는 블록의 너비나 렌더 객체의 스타일 속성, 박스 모델을 고려해 계산된다.
- 자식 렌더링 객체를 배치
- 자식 렌더링 객체들의 x, y값을 지정한다.
- 부모 혹은 자식 객체가 ‘더티’한 경우 재계산이 필요하다. 자식 렌더링 객체의
layout()
메서드를 호출해 높이를 계산한다.
- 자식 렌더링 객체의 높이를 더해 부모 렌더 객체의 높이를 계산한다.
- 레이아웃 중인 렌더 객체의 ‘더티’ 플래그를 제거한다.
레이아웃이 발생할 경우 부모, 자식 요소들의 크기를 재계산해야 하고 하위 요소들에 모두 영향을 주기 때문에 부하가 매우 크다. 따라서 빠르게 웹 페이지를 렌더링하기 위해서는 불필요한 레이아웃을 발생시키지 않는 것이 중요하다.
페인트(Paint)
지금까지 렌더 트리를 만들며 DOM 요소의 위치, 스타일 등을 계산했다. 하지만 아직 화면을 그리는 데에 필요한 단계가 더 존재한다. 요소의 크기, 위치는 알지만 같은 위치에 그려지는 여러 노드가 있다면 어떤 순서로 그려야 할까? 만약 z-index나 float, position 같은 CSS 프로퍼티를 이용해 레이어의 순서를 변경한다면 렌더 트리의 순서가 레이어의 순서와 일치하지 않을 것이다. 페인트 단계에서는 렌더 트리를 순회하며 레이어를 만들고 레이어의 배경, 테두리, 텍스트, 그려지는 순서, 레이어 간의 순서 등 그려지는 과정을 기록한다.
합성(Compositing)
이 단계에서는 그려질 요소들의 순서, 스타일, 위치 등을 모두 알고 있다. 이 정보를 화면의 픽셀로 변환하는 것을 래스터화(rasterizing)라고 한다. 합성(compositing)은 각 레이어를 분리해서 래스터화한 뒤 브라우저에서 페이지의 크기, 뷰포트에 맞게 합성해 화면으로 나타낸다. 모던 브라우저의 경우 레이어를 래스터화한 뒤 조각화한 타일로 만들어 저장한다. 그리고 이후 뷰포트가 변경되었을 때 타일을 변경해가며 빠르게 보여준다.
지금까지 살펴본 HTML, CSS, 자바스크립트를 화면의 픽셀로 나타내기 위한 이런 과정을
주요 렌더링 경로(Critical Rendering Path, CRP)
라고 부른다.
>![]()
CRP 과정에서 렌더 트리를 만들고 이 결과를 이용해 레이아웃을 수행하며, 페인트를 진행한다. 이런 연쇄적인 구조 때문에 초기 계산이 필요한 변화를 발생시킨다면 화면을 업데이트할 때 더 많은 시간을 사용하게 된다.
CRP가 중요한 이유는 브라우저가 어떻게 화면을 렌더링하는지 알 수 있을 뿐만 아니라 성능에도 큰 영향을 미치는 과정이기 때문이다. 페이지의 초기 로딩 성능 문제나 버벅거림 문제를 해결할 때 CRP의 어느 단계에서 문제가 발생하는지 파악할 수 있어야 한다.
브라우저별 렌더링 엔진
- Chrome : Blink, Webkit(모바일 iOS Chrome)
- Safari : Webkit
- IE : Trident
- IE Edge : EdgeHTML -> Blink
- Firefox : Gecko
Webkit
애플에서 개발되었으며 Safari나 iOS의 웹 브라우저를 개발하기 위해 만들었다. Webkit은 Tizen 모바일 OS나 아마존 킨들 보드 등에서도 사용된다. 자유 소프트웨어 조직이었던 KDE의 KHTML, KJS를 포크해 만들어졌으며 HTML, SVG 등을 렌더링하기 위해 사용하는 WebCore와 자바스크립트 엔진인 javaScriptCore 등 여러 컴포넌트로 구성되어 있다. 2013년 Google은 WebCore를 포크해 현재 크롬의 엔진인 Blink를 만들게 된다.
Blink
Webkit의 WebCore를 포크해 개발되었으며 현재는 Chromium 프로젝트에 참여하고 있는 구글, 어도비, 인텔, 삼성 등 여러 개발자에 의해 운영되고 있다. 크롬, MS Edge, 오페라, 안드로이드 웹뷰, 삼성 브라우저 등 Chromium 기반 브라우저에서 사용하고 있으며 전 세계에서 가장 널리 사용되고 있다.
Gecko
Mozilla 재단에 의해 개발되었으며, 현재도 개발되고 있다. Gecko는 1997년 Netscape에서 사용하기 위해 개발되었으며 1998년 Mozilla 재단이 만들어지며 Gecko는 오픈 소스화되었다. 현재는 Firefox에서 사용 중이다.
트라이던트(Trident)와 EdgeHTML
마이크로소프트에서 개발되었으며 윈도우 IE4부터 IE11까지 꾸준하게 사용된 렌더링 엔진이다. MSHTML로도 알려져 있으며 트라이던트에서 분기되어 나온 EdgeHTML이 Edge 브라우저에서 사용되었다. EdgeHTML은 Edge 브라우저를 위해 만들어졌으며 오래된 IE의 모든 레거시 코드를 제거하고 웹 표준을 맞추기 위해 대부분의 코드가 다시 작성되었다. 2015년 첫 등장을 했지만 웹의 호환성을 위해 Chromium 기반의 Edge로 업데이트 되었고 EdgeHTML의 새로운 버전 업데이트는 2018년 이후로 더는 나오지 않고 있다.
<참고 : https://minemanemo.tistory.com/121
https://d2.naver.com/helloworld/9274593 >