웹 브라우저의 구조
-
User Interface: 주소 표시줄, 이전/다음/새로고침 버튼 등 요청한 페이지를 보여주는 창을 제외한 나머지 모든 부분
-
Rendering Engine: HTML과 CSS를 파싱하여 요청한 웹 페이지를 표시하는 렌더링 엔진
-
Browser Engine: User Interface와 Rendering Engine을 연결하는 브라우저 엔진
-
Networking: HTTP 요청과 같은 각종 네트워크 요청을 수행하는 네트워킹 파트
-
UI Backend: 체크박스나 버튼과 같은 기본적인 위젯을 그려주는 UI 백엔드 파트
-
Data Persistence: localStorage나 Cookie와 같이 보조 기억장치에 데이터를 저장하는 파트
-
Javascript Interpreter: JS코드를 실행하는 인터프리터
※ 크롬은 대부분의 브라우저와 달리 각 탭마다 별도의 렌더링 엔진 인스턴스를 유지하여, 각 탭은 독립된 프로세스로 처리된다.
렌더링 엔진
종류
Safari: Webkit
Firefox: Gecko
Chrome: Blink
역할
요청 받은 내용을 브라우저 화면에 표시하는 일. 렌더링 엔진은 HTML, XML, 이미지를 표시할 수 있다.
렌더링 엔진의 목표
- HTML, CSS, JS, 이미지 등 웹 페이지에 포함된 모든 요소들을 화면에 보여준다
- 업데이트(사용자 동작으로 인해 입력이 발생한다던가, 스크롤이 생긴다던가, 애니메이션이 동작한다던가, 비동기 요청으로 인한 데이터 로딩)가 필요할 때, 효율적으로 렌더링을 할 수 있도록 자료 구조를 생성한다
렌더링 엔진의 동작 과정
- 렌더링 엔진은 좀 더 나은 사용자 경험을 위해 가능하면 빠르게 내용을 표시한다. 모든 HTML을 파싱할 때까지 기다리지 않고 배치와 그리기 과정을 시작한다. 네트워크로부터 나머지 내용이 전송되기를 기다리는 동시에 받은 내용의 일부를 먼저 화면에 표시한다.
- DOM Tree 생성
- 토큰화 과정: 렌더링 엔진이 HTML 문서를 parsing 하여 HTML5 표준에 지정된 고유한 토큰으로 변환된다.
- 렉싱 과정: 각 토큰이 해당 속성과 규칙을 정의하는 노드 객체로 변환된다. 각 노드가 연관성을 가질 수 있도록 트리를 생성한다.
- 렌더링 엔진은 HTML 문서 파싱 중에 JS, CSS 같이 추가로 필요한 파일들을 불러오도록 요청하기도 한다.
- HTML 파싱이 완료되면 파싱 이후에 실행되어야 하는
defer
모드 script를 파싱하기 시작한다. 즉, defer
모드 script는 HTML파싱을 중단하지 않는다. async
모드 script는 별도의 컨텍스트에 의해 다운로드한 후 파싱하고 즉시 실행된다. (HTML 파싱과 비동기적으로 파싱이 일어난다)
- HTML 문서 내의 모든 것은 DOM을 구성한다.
최상위에는 document 객체가 있으며, 태그는 element node가 되고 각 태그의 attribute는 attributeNode , text의 경우 텍스트 노드가 되어 DOM을 구성한다. 주석도 커멘트 노드가 된다.
- CSSOM Tree 생성
- DOM이 어떻게 화면에 표시될 지를 알려주는 역할을 한다. CSS도 위에서 아래로 스타일 규칙이 정해지기 때문에 이 또한 트리구조를 가지고 있다.
- Render Tree
- DOM 트리와 CSSOM 트리를 합쳐서 렌더 트리를 생성한다.
- 렌더 트리: 화면에 표시되어야 할 모든 노드의 컨텐츠, 스타일 정보를 포함하는 트리
- document 객체부터 각 노드를 순회하면서 각각에 맞는 CSSOM을 찾아서 규칙을 적용합니다. 그러면서 렌더와 관련된 요소들을 렌더 트리에 포함시키게 된다. meta 요소, head 요소와 같은 비시각적 요소와 display: none 속성을 가진 요소들은 렌더와 관계가 없기 때문에 렌더 트리에 포함되지 않는다.
- Layout(Reflow)
- 뷰포트 내에서 요소들의 위치와 크기를 계산하는 과정
- 텍스트나 요소의 박스가 화면에서 차지하는 영역이나 여백 그리고 이외의 스타일 속성이 계산됩니다.
- CSS에서 %나 em 같은 상대적인 단위를 사용했을 때는 이게 뷰포트에 맞춰서 픽셀단위로 변환된다.
- Paint(Repaint)
- 렌더 트리에 포함된 요소들이나 텍스트, 이미지들이 실제 픽셀로 그려집니다.
UI가 업데이트되는 3가지 상황
1. Layout부터 다시 발생하는 경우
요소의 크기나 위치가 바뀌거나, 브라우저 창의 크기가 바뀌었을 때 발생
2. Paint부터 다시 발생되는 경우
배경 이미지나 텍스트 색상, 그림자 등 레이아웃의 수치를 변화시키지 않는 스타일의 변경이 일어났을 때 발생
3. 레이어의 합성(Composite)만 다시 발생하는 경우
레이어: 포토샵의 레이어와 비슷하게 페인팅할 영역을 나누어 놓는 것을 의미
크롬의 경우, 레이아웃 과정 이후에 정해진 기준이나 필요에 의해서 브라우저가 레이어를 생성한다. 그리고 렌더 트리에 있는 노드 객체들은 생성된 레이어에 포함되게 됩니다.
레이어는 트리 형태로 구성이 된다. 렌더링 엔진이 각 레이어를 페인팅 과정에서 그려준 다음에 하나의 비트맵으로 합성해서 페이지를 완성
Layout과 Paint를 수행하지 않고 레이어의 합성만 발생하기 때문에 성능상으로 가장 큰 이점을 가진다.
렌더링 엔진의 스레드
렌더링 엔진은 통신을 제외한 거의 모든 경우에 단일 스레드로 동작한다. (Q. async script의 경우 병렬로 동작하지 않을까?) 파이어폭스와 사파리의 경우 렌더링 엔진의 스레드는 브라우저의 주요한 스레드에 해당한다. 크롬에서는 이것이 탭 프로세스의 주요 스레드이다.
통신은 몇 개의 병렬 스레드에 의해 진행될 수 있는데 병렬 연결의 수는 보통 2개에서 6개로 제한된다(예를 들면 파이어폭스 3은 6개를 사용).
Reference