[웹개발] 브라우저의 작동 원리
Introduction
이번 문서에서는 웹개발에서 알아두면 좋은 브라우저의 작동 원리 에 대해 알아보도록 하겠습니다.
사실 웹브라우저는 세계에서 가장 많이 쓰이는 소프트웨어이지만 브라우저의 기능은 웹개발에서 그렇게까지 중요한 분야가 아닙니다. HTML/CSS/Javascript 만 알면 프론트엔드를 개발할 수 있고, 브라우저는 웹서버의 내용을 자동으로 렌더링해서 띄워주기 때문에 굳이 그것까지? 라는 생각이 이제까지 지배적이었습니다.
다만 웹상에서 사용하는 태그와 기능이 다양해지면서 브라우저 호환성 이슈가 불거지기 시작합니다.
같은 웹서버의 내용을 브라우저별로 다르게 fetching 하거나,
이미지 사이사이 지정하지 않았던 여백이 뜬다거나 하는 등 알수 없는 오류가 작동하기도 합니다. 여러분들도 특정 서비스를 이용할때 크롬에서 더 잘된다거나, 파이어폭스에서 잘 된다거나 하는 경우가 있었을 것입니다.
이렇듯 브라우저가 어떻게 동작하지? 라는 담론이 몇년 전부터 형성되어 왔고, 오늘 그 담론에 대한 답으로 아래 링크를 참고하여 브라우저의 작동 원리 를 간략하게 설명합니다.
https://www.html5rocks.com/en/tutorials/internals/howbrowserswork/
웹 브라우저와 웹 서버
브라우저의 기능에 설명하기에 앞서 FE(Front-end) 에서 브라우저는 어떤 역할을 수행하는지 짚고 가겠습니다.
웹브라우저가 웹서버에 웹페이지 요청을 하면 웹서버는 웹페이지 응답을 합니다.
서버가 브라우저에게 전달한 응답인 HTML문서를 브라우저는 읽어들이고 해석한 후 사용자(Client) 에게 보여줍니다.
HTML 및 CSS를 해석하는 구체적인 내용들은 모두 W3C, World Side Web Consortium 에 의해 관리되고 유지됩니다. 지난 몇년간 브라우저들은 각자 이러한 구체적 규정들의 일부만 충족하며 각 브라우저별 확장 기능을 개발해 왔습니다. 브라우저별 호환성 이슈가 발생할 수밖에 없는 거죠.
웹 브라우저의 구조와 렌더링 엔진
주소창, 뒤로/앞으로 버튼 등을 포함한 User Interface, UI와 렌더링 엔진(Rendering engine) 사이에서 중간 매체 역할을 수행하는 브라우저 엔진(Browser engine), 웹서버로부터 응답 받은 내용을 UI 상에 나타내주는 렌더링 엔진, 웹서버와 통신이 가능하게 하는 네트워크, UI 구동이 가능하게 하는 UI 백엔드, 자바스크립트 코드를 파싱하고 실행하는 자바스크립트 해석기(Javascript interpreter), 쿠키와 같은 로컬 데이터를 저장하는 데이터 스토리지(Data storage, Data persistence)로 구성됩니다.
이 중 가장 핵심적인 역할을 담당하는 렌더링 엔진의 경우 사용자가 요청해서 웹서버가 응답한 HTML 문서를 HTML과 CSS로 파싱해서 화면을 구성합니다. 렌더링 엔진은 여러 개의 인스턴트를 한 번에 구동할 수 있습니다. 서로 다른 브라우저는 기본적으로 다른 렌더링 엔진을 사용하는데요. 인터넷 익스플로러(IE)는 Trident를, FireFox는 Gecko를, 사파리는 Webkit을 사용합니다. 구글 크롬과 오페라 브라우저는 Webkit의 일종인 Blink를 사용합니다. Webkit은 오픈소스 렌더링 엔진으로 원래 리눅스 플랫폼에 사용되었습니다.
렌더링 엔진은 웹서버로부터 전달받은 HTML 문서를 맨 처음 네트워크 레이어에서 불러옵니다.
렌더링 엔진 작동 방식
렌더링 엔진은 웹서버로부터 전달받은 HTML 문서를 맨 처음 네트워크 레이어에서 불러옵니다. 그리고 아래와 같은 기본적인 Flow 를 거칩니다. (세부적인 플로우 및 각 개념을 어떤 이름을 붙이는지는 브라우저별로 다를 수 있지만 우선 기본적인 단계는 아래와 같습니다.)
- HTML 파싱 후 DOM 트리 만들기
- 렌더 트리(Render Tree) 만들기
- 렌더 트리(Render Tree) 레이아웃 만들기
- 렌더 트리 페인팅 (Renter Tree Painting)
1. HTML 파싱 후 DOM 트리 만들기
렌더링 엔진은 우선 네트워크 레이어를 통해 전달받은 HTML 문서(Source code)를 파싱(Parsing) 하여 각 요소들을 DOM Tree(Contents Tree)의 각 DOM 노드 들로 전환합니다. DOM이란 Document object model 의 준말로 마크업 형태의 HTML 문서를 오브젝트 모델의 형태로 바꿔놓은 것입니다. 당연히 HTML 문서의 각 마크업과 DOM의 각 요소는 1:1 매칭됩니다.
<html>
<body>
<p>
Hello World
</p>
<div> <img src="example.png"/></div>
</body>
</html>
ㄴ HTML, Body 부모 태그 안에 단락을 나타내는 p 태그, 한 요소를 나타내는 div 태그가 자식 태그로 존재함. 이 코드를 DOM Tree로 전환할 때 아래와 같이 구성됨.
2. 렌더 트리(Render Tree) 만들기
HTML 문서들을 파싱하여 DOM Tree를 구성한 후, 렌더링 엔진은 CSS/Style 데이터를 파싱하고 그 스타일 데이터들로 렌더 트리(Render Tree)를 만듭니다. DOM 트리가 웹 상에 나타날 내용(Contents)를 구성한다면 렌더 트리는 시각적 요소, 어떻게 나타날지 그 스타일을 지정합니다. 렌더 트리는 색상, 차원 등 시각적 지침들을 담은 정사각형들로 구성됩니다. 그 정사각형들은 스크린에 맞는 순서대로 정렬되어야 하죠.
렌더 트리 각각의 정사각형에 해당하는 Renderer 렌더러 들은 DOM 트리 요소(element)들에 적용되지만 1:1 관계가 성립되는 것은 아닙니다. 시각적이지 않은 DOM 요소들은 렌더 트리에 삽입될 수 없습니다. <head> 태그 안의 요소들은 화면에 나타나는 값들을 포함하지 않습니다. 따라서 그 어떤 Renderer도 적용될 수 없죠. 어떤 렌더러들은 DOM 노드에 적용될 수 있으나 꼭 트리의 같은 위계에 속할 필요는 없습니다.
3. 렌더 트리(Render Tree) 레이아웃 만들기
레이아웃을 만든다는 것은 각 노드들에게 스크린의 어느 공간에 위치해야 할지 각각의 값(Positionm, Size)을 부여하는 것을 의미합니다.
4. 렌더 트리 페인팅 (Renter Tree Painting)
렌더 트리가 만들어져 레이아웃이 구성되었다면, UI 벡엔드가 동작하여 각 노드들을 정해진 스타일 및 위치값대로 화면에 배치합니다.
더 나은 UX(User experience)를 위해, 렌더링 엔진은 각 콘텐츠를 가능한한 빨리 스크린에 띄워야 합니다. 따라서 모든 HTML 요소들을 렌더링 엔진으로 넣어서 한번에 출력하는 것이 아니라, 일부 콘텐츠는 먼저 트리 과정을 거쳐 스크린에 나타나고, 그 와중에 웹의 다른 요소들은 네트워크를 통해 렌더링 엔진으로 읽어들어 오는 순차적인 방식으로 입출력이 진행됩니다.