ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Web] 브라우저는 어떻게 동작하는가?
    👩🏻‍💻 정리/Web 2022. 11. 19. 00:14

    이번 주에는 코딩 과제 말고 연구글 과제도 주어졌다. 참고 문서를 바탕으로 브라우저 동작 원리에 대해 정리하기! 이건 한 1년 전에 한번 읽었었던 문서인데, 웹 개발자라면 무조건 알고 있어야 하는 지식이라고 생각된다. 실제로 면접 때 브라우저 동작 원리에 대해서 간단하게 설명해달라는 질문을 받은 적이 있었는데, 뭔가 둥둥 떠다니는 지식이 말로는 제대로 인출되지 않아 곤욕스러웠던 경험이 있다. 이 기회에 면접에서도 술술 대답할 수 있게 다시 제대로 정리해보자!


    1. 브라우저란?

    브라우저 또는 웹 브라우저는 웹 서버에서 이동하며 쌍방향으로 통신하고 HTML 문서나 그림, 멀티미디어 파일을 출력하는 월드 와이드 웹(WWW)을 기반으로 한 응용 소프트웨어를 말한다. 주요 웹 브라우저로는 파이어폭스(모질라), 크롬(구글), 인터넷 익스플로러/마이크로소프트 엣지(마이크로 소프트), 오페라, 사파리 등이 있다.

    2. 브라우저의 주요 기능

    브라우저의 주요 기능은 사용자가 선택한 자원을 서버에 요청하고 브라우저에 표시하는 것이다. 자원은 보통 HTML 문서지만 PDF나 이미지 또는 다른 형태일 수 있다. 자원의 주소는 URI(Uniform Resource Identifier)에 의해 정해진다. 브라우저는 HTML, CSS 명세에 따라 HTML 파일을 해석해서 표시하는데 이 명세는 웹 표준화 기구인 W3C(World Wide Web Consortium)에서 정한다.

    💡 URI란?
    '통합 자원 식별자'라는 뜻으로, 인터넷에 있는 자원을 나타내는 유일한 주소이다. URI의 존재는 인터넷에서 요구되는 기본 조건으로서 인터넷 프로토콜에 항상 붙어 다닌다. URI의 하위 개념으로 URL, URN이 있다.

    3. 브라우저 기본 구조

    브라우저의 주요 구성 요소는 아래 사진과 같다.

    브라우저를 구성하는 다양한 레이어들 간의 관계

    1. 사용자 인터페이스
      주소 표시줄, 이전/다음 버튼, 북마크 메뉴 등.
      요청한 페이지를 보여주는 창을 제외한 나머지 모든 부분.
    2. 브라우저 엔진
      사용자 인터페이스와 렌더링 엔진 사이의 동작을 제어.
    3. 렌더링 엔진
      요청한 콘텐츠를 표시.
      예를 들어 HTML을 요청하면 HTML과 CSS를 파싱하여 화면에 표시.
      파이어 폭스는 모질라에서 직접 만든 게코(Gecko) 엔진을 사용하며 사파리와 크롬은 웹킷(Webkit) 엔진을 사용.
    4. 통신
      HTTP 요청과 같은 네트워크 호출에 사용.
      이것은 플랫폼 독립적인 인터페이스이고 각 플랫폼 하부에서 실행.
    5. UI 백엔드
      콤보 박스와 창 같은 기본적인 장치를 그림.
      플랫폼에서 명시하지 않은 일반적인 인터페이스로서, OS 사용자 인터페이스 체계를 사용.
    6. 자바스크립트 해석기
      자바스크립트 코드를 해석하고 실행.
    7. 자료 저장소
      이 부분은 자료를 저장하는 계층으로,
      쿠키를 저장하는 것과 같이 모든 종류의 자원을 하드 디스크에 저장할 필요가 있음.
      HTML5 명세에는 브라우저가 지원하는 '웹 데이터 베이스'가 정의되어 있음.
    💡 (tmi) 근데 크롬은 렌더링 엔진을 탭마다 가지고 있다고?
    크롬은 대부분의 브라우저와 달리 각 탭마다 별도의 렌더링 엔진 인스턴스를 유지하여 각 탭은 독립적인 프로세스로 처리된다. 대부분의 브라우저는 하나의 프로세스로 모든 탭을 관리하고 있는데, 수많은 탭 가운데 하나만 에러가 나도 브라우저 전체가 꺼지는 단점이 있었다. 크롬은 이를 보완하기 위해 각 탭마다 독립된 프로세스를 이용하여  비록 메모리는 많이 먹지만, 에러가 발생하게 되면 에러가 발생한 탭만 꺼지는 식으로 안정성을 확보하였다. 또한 탭 별로 개별 프로세스를 두는 방식의 진정한 장점은 보안성에 있다.

    4. 렌더링 엔진

    이 중 좀 더 자세히 보아야 할 부분은 바로 렌더링 엔진이다. 렌더링 엔진의 역할은 요청받은 내용을 브라우저 화면에 표시하는 일이다. HTML 및 XML 문서와 이미지를 표시할 수 있으며, 플러그인이나 브라우저 확장 기능을 이용해 PDF와 같은 다른 유형 또한 표시할 수 있다. 브라우저 엔진마다 해석 방식이 조금씩 다를 수 있지만, 대부분 아래와 같이 크게 4단계로 나눠져 있다.

    렌더링 엔진의 동작 과정

    1. 렌더링 엔진은 HTML 문서를 파싱하고 "콘텐츠 트리" 내부에서 태그를 DOM 노드로 변환한다. 그다음 외부 CSS 파일과 함께 포함된 스타일 요소도 파싱한다.
    2. 스타일 정보와 HTML 표시 규칙은 "렌더 트리"라고 부르는 또 다른 트리를 생성한다. 렌더 트리는 색상 또는 면적과 같은 시각적 속성이 있는 사각형을 포함하고 있는데 정해진 순서대로 화면에 표시된다.
    3. 렌더 트리 생성이 끝나면 배치가 시작되는데 이것은 각 노드가 화면의 정확한 위치에 표시되는 것을 의미한다.
    4. 다음은 UI 백엔드에서 렌더 트리의 각 노드를 가로지르며 형상을 만들어 내는 그리기 과정이다.

    렌더링 엔진들은 좀 더 빠르고 쾌적한 UX를 위해 가능한 한 빨리 내용을 표시하는데 모든 HTML을 파싱할 때까지 기다리는 것이 아닌 배치와 그리기 과정부터 시작한다. 그런 후 네트워크로부터 나머지 내용(사용자 이름이나 글 제목, 본문 등)을 전송받는 대로 화면에 표시한다. 이런 과정을 통해 사용자는 빈 화면을 보며 기다리지 않고 화면이 그려지는 것부터 볼 수 있는 것이다.

    5. 파싱

    렌더링 엔진의 동작 과정 첫 번째인 파싱(Parsing)은 토큰화된 코드를 구조화하는 과정을 말한다. 이러한 파싱 과정을 전문적으로 해주는 부분을 파서(Parser)라고 부른다. 파싱 과정은 정해진 문법들을 모두 따르는지 확인하는 과정이다. 이때 브라우저는 HTML, CSS, JavaScript 세 종류의 언어를 해석하는데, 그중에서 JavaScript는 렌더링 엔진 레이어가 아닌 JavaScript 해석기라는 별도의 레이어에서 언어를 해석한다. 따라서 렌더링 엔진에서는 HTML, CSS를 파싱한다.

    5.1 HTML 파싱

    파싱 흐름도

    브라우저는 토큰화된 HTML 문자열들을 이용해 파스 트리(Parse Tree)를 생성한다. 파스 트리는 브라우저가 읽어야 할 HTML 코드를 트리 모양으로 구조화하여 나타낸 것으로 브라우저는 파스 트리를 이용해 DOM 트리를 구축한다.

    HTML 파서는 다른 파서와 비교했을 때 조금 독특한 특징을 가지고 있다. 첫 번째 특징은 오류에 너그러운 속성이다. HTML 파싱하는 도중 어떠한 에러가 발생한다면, 브라우저는 자체적으로 에러를 복구하려고 한다. 그래서 가끔 태그들을 제대로 닫아주지 않더라도 브라우저가 원하는 대로 출력되는데 이는 이러한 특징 덕분이다.

    두 번째 특징으로는 파싱 과정이 중단될 수 있다는 것이다. HTML은 파싱 도중 <script>, <link>와 같은 외부 태그를 만나게 되면 HTML 파싱을 즉시 중단하고 해당 태그의 해석을 실행한다. 만약 해당 태그가 외부 파일을 참조하고 있다면, 외부 파일을 다운로드한 후 해석을 다시 시작한다. 

    세 번째 특징은 재시작이다. 앞서 말한 것처럼 HTML의 파싱 과정은 어떠한 외부의 요인으로 인해 방해받을 수 있다. 파싱 중간에 외부 요인으로 인해 DOM이 추가되거나 변경, 삭제가 일어날 수 있고, 이렇게 되는 경우 HTML은 처음부터 다시 파싱 과정을 거친다. 즉, 바이트를 문자로 변환하고, 토큰을 식별한 후 노드로 변환하고 DOM 트리를 빌드한다. 이 때문에 처리해야 할 HTML이 많을 때에는 파싱 시간이 오래 걸릴 수 있다.

    5.2 CSS 파싱

    CSSOM

    일반적으로 CSS를 링크하는 코드가 HTML 코드 내에 삽입되어 있기 때문에, HTML을 파싱하는 도중에 CSS 파싱이 시작된다. 네트워크를 통해 먼저 받아온 코드부터 해석을 실행할 수 있는 HTML 파서와는 달리, CSS 파서는 전체 파일을 모두 다운로드할 때까지 파싱을 시작할 수 없다.

    전체 CSS 파일을 다운로드한 후, CSS 파싱 과정이 끝나면 코드에서 명세한 내용과 순서를 바탕으로 CSSOM(CSS Object Model) 트리라고 부른다.

    6. 렌더 트리 구축

    DOM + CSSOM = 렌더 트리

    DOM 트리가 구성되는 동안 브라우저는 렌더 트리를 구성하기 시작한다. 렌더 트리는 기본적으로 화면에 나타나는 요소들을 결정하는 트리이다. 즉, 어떠한 요소들이 보여지고 숨겨져야 하는지, 어떤 스타일이 적용되어야 할지, 그리고 어떤 순서로 나타낼 것인지를 명세하는 트리이다.

    위 사진처럼 렌더 트리는 DOM 트리와 CSSOM 트리를 조합하여 만들어지고, 이때 화면에 그려지지 않는 요소들은 트리에 나타나지 않는다. 예를 들어 <head>, <script> 같은 태그나 display: none 스타일이 적용된 엘리먼트 등이 이에 해당된다.

    7. 레이아웃 or 리플로우

    리플로우(레이아웃) 과정

    렌더 트리 구성이 끝나면 레이아웃 단계가 이어진다(모질라에서는 이를 리플로우라고 부름). 레이아웃 단계에서는 렌더 트리에서 계산되지 않았던 노드들의 크기와 위치, 레이어 간 순서와 같은 정보를 계산하여 좌표에 나타낸다. 이 과정은 HTML의 루트 오브젝트로부터 재귀적으로 실행된다.

    레이아웃은 계산 범위에 따라 전역적 레이아웃과 증분적 레이아웃으로 나뉘는데, 전역적 레이아웃은 말 그대로 화면 전체의 레이아웃을 계산하는 것이다. 하지만 전역적 레이아웃 단계는 모든 렌더 트리 노드에 대해 기하학적인 계산을 수행하기 때문에 자연스럽게 노드가 많아지고 속도가 느려지게 된다. 따라서 브라우저는 자체 최적화 로직을 탑재하고 있는데, 그중 하나가 바로 더티 비트 시스템(Dirty Bit System)이다. 더티 비트 시스템은 특정 엘리먼트의 레이아웃이 변경되었을 때, 렌더 트리를 처음부터 재탐색하지 않고, 특정 부분만 다시 계산하여 리소스의 낭비를 줄이는 최적화 방법이다.

    증분적 레이아웃은 이러한 더티 비트 시스템을 활용하여 레이아웃 과정에서 렌더 트리를 재귀적으로 탐색하다가 레이아웃 변경이 발생해야 하는 엘리먼트를 만나게 되면 그 계산을 즉시 수행하지 않고, 스케줄러를 통해 비동기로 일괄 작업(batch)을 진행한다. 이를 통해 연산과 횟수와 범위를 줄일 수 있다.

    8. 페인트

    페이트 단계는 말 그대로 레이아웃 단계를 통해 배치된 엘리먼트들에게 색을 입히고 레이어의 위치를 결정하는 단계이다. 이 단계 역시 루트 오브젝트로부터 재귀적으로 실행이 되고, 레이아웃과 마찬가지로 전역적 페인팅과 증분적 페인팅이 있다. 또한 z-index가 낮은 순서대로 먼저 페인팅된다.


    참고

    🔗 브라우저는 어떻게 동작하는가?
    🔗 프론트엔드 개발자라면 알고 있어야 할 브라우저의 동작 과정