티스토리 뷰

목차

웹 브라우저의 구조
웹 브라우저의 렌더링 과정
재배치(Reflow)와 다시 그리기(Repainting)
최적화

웹 브라우저의 렌더링 과정을 파악하는 것은 웹 개발자로서 꼭 필요하다고 생각한다.
Javascript를 통해 요소를 조작하고 스타일을 변경하는 과정에서 재배치(Reflow)와 다시 그리기(Repainting)가 이루어지며 이를 최소화할수록 더 나은 성능과 사용자 경험을 제공하기 때문이다.

웹 브라우저의 구조


browser

  1. 사용자 인터페이스
    주소 표시줄, 이전/다음 버튼, 북마크 메뉴 등. 요청한 페이지를 보여주는 창을 제외한 나머지 모든 부분이다.
  2. 브라우저 엔진
    사용자 인터페이스와 렌더링 엔진 사이의 동작을 제어한다.
  3. 렌더링 엔진
    요청한 콘텐츠를 표시한다. 예를 들어 요청 후 전송받은 문서의 HTML과 CSS를 파싱하여 화면에 표시한다.
  4. 통신
    HTTP 요청과 같은 네트워크 호출에 사용된다.
  5. UI 백엔드
    렌더링 엔진에 의해 구축된 Render 트리의 노드들을 화면에 배치하고 그린다.
  6. 자바스크립트 해석기
    자바스크립트 코드를 해석하고 실행한다.
  7. 자료 저장소
    이 부분은 자료를 저장하는 계층이다. 쿠키를 저장하는 것과 같이 모든 종류의 자원을 하드 디스크에 저장할 필요가 있다. HTML5 명세에는 브라우저가 지원하는 '웹 데이터 베이스'가 정의되어 있다.

웹 브라우저의 렌더링 과정


browser_rendering

  1. DOM 트리, CSSOM 트리 구축 : 브라우저의 렌더링 엔진이 HTML 마크업을 파싱하여 DOM 트리를, CSS 마크업을 파싱하여 CSSOM 트리를 구축.
  2. Render 트리 구축 : DOM 트리와 CSSOM 트리를 결합하여 Render 트리를 구축.
  3. Layout 배치 : 구축된 Render 트리를 탐색하며 크기와 위치 정보를 기반으로 Layout을 배치.
  4. 그리기 : Render 트리를 탐색하며 구성된 노드의 정보에 따라 화면에 표현.

1) DOM, CCSOM 구축

먼저 브라우저는 디스크에서 가져오거나 서버에서 응답받은 문서의 Byte를 문자열로 변환한다.
그 후 어휘 분석기(lexical analysis)가 문서 내 HTML 마크업과 CSS 마크업을 토큰화하며 노드를 생성하며 각각 DOM 트리와 CSSOM 트리를 구축한다.

HTML 마크업을 파싱할 때 스크립트 태그를 만나면 스크립트 엔진이 제어권을 얻고 스크립트 코드를 실행하는데 이 때 스타일 정보를 요청할 수 있다. 하지만 CSSOM이 아직 구축 되지 않았다면 필요한 스타일 정보를 가져올 수 없기 때문에 문제가 생긴다.
이 문제를 파이어폭스는 아직 로드 중이거나 파싱 중인 스타일 시트가 있는 경우 모든 스크립트의 실행을 중단하는 방법으로 해결하며 웹킷은 로드되지 않은 스타일 시트 가운데 문제가 될만한 속성이 있을 때에만 스크립트를 중단하는 것으로 해결한다.

2) Render 트리 구축

구축된 DOM 트리와 CSSOM 트리를 결합하여 연결(Attachment)한다.
이 때 화면에 표현할 필요가 없는 노드(meta tag, script tag, ...)들은 Render 트리에서 제외된다.
반면에 화면에 보이지는 않지만 공간을 차지하는 노드(visibility:hidden, ...)들은 Render 트리에 포함된다.
즉, Render 트리는 화면에 표현되는 내용들로 구성된다.

3) 배치(Layout)

Render 트리 내 노드들이 각자의 사이즈와 위치에 따라 문서에 정확하게 표현되도록 계산한다.

4) 그리기

Render 트리를 탐색하며 노드들의 스타일 속성에 맞게 화면에 표현하고 이로써 렌더링 과정이 완료된다.
여기서 렌더링 엔진은 모든 HTML을 파싱할 때까지 기다리지 않고 배치와 그리기 과정을 함께 진행한다. 즉, 서버에서 응답받은 문서를 전송받는 도중에 이미 받은 부분을 파싱하고 화면에 표시해가는 것이다.

재배치(Reflow)와 다시 그리기(Repainting)


처음 화면이 로딩될 때 위 렌더링 과정을 통해 화면이 그려진다. 그 후 사용자의 인터렉션에 의해 요소가 변경되는 일이 생긴다. 이렇게 Render 트리가 변경되면서 재배치나 다시 그리기가 발생한다. 이 과정이 빈번하게 발생할 수록 성능 및 사용자 경험이 저하되기 때문에 이를 최소화하는 것이 좋다.

- 재배치(Reflow)

인터렉션 등에 의해 변경되어야 할 Render 트리의 사이즈와 위치를 다시 계산하는 것을 말한다. 이 때 영향을 받은 부모 및 자식 노드도 재배치가 발생할 수 있으며, 경우에 따라 문서 전체가 재배치될 수도 있다.

- 다시 그리기(Repainting)

재배치가 발생하거나 요소의 색상 등이 변경된 경우, 다시 화면에 표현하는 것을 말한다.

최적화


요소의 스타일이 변경될 때 혹은 재배치가 발생할 때 다시 그리기가 발생한다. 재배치 작업은 다시 그리기 작업을 필연적으로 동반하며 경우에 따라 Render 트리 전체를 재구성할 수도 있으므로 다시 그리기만 발생할 때에 비해서 비용이 훨씬 비싸다.
그래서 이를 최적화할수록 더 나은 퍼포먼스와 사용자 경험을 제공할 수 있다. 그럼 최적화 방법에는 무엇이 있을까?

- DOM의 depth를 최소화한다.

당연한 말이지만 DOM의 깊이와 크기를 작게 구성할수록 재배치가 더 빨리 처리된다.

- 스타일의 변경을 한번에 한다.

var myelement = document.getElementById('myelement');
myelement.width = '100px';
myelement.height = '200px';
myelement.style.margin = '10px';

위 코드를 아래처럼 변경하여 한번에 처리한다.

var myelement = document.getElementById('myelement');
myelement.classList.add('newstyles');
.newstyles {
    width: 100px;
    height: 200px;
    margin: 10px;
}

- 주변에 영향을 주는 요소를 제한한다.

인터렉션에 의해 크기나 위치나 변경되는 요소는 변경될 때 주변 요소들이 최대한 영향받지 않도록 정의한다.

- 개발자 도구를 이용하여 분석한다.

메인 브라우저들은 개발자 도구를 이용하여 재배치와 다시 그리기가 얼마나 발생하는지 확인할 수 있다.
재배치 및 다시 그리기는 타임 라인에서 녹색으로 표현되며 이를 통해 최적화를 시도한다.
크롬의 경우 Performance탭에서 record한 결과의 main항목을 선택한 뒤 painting영역으로 확인할 수 있다.

- 라이브러리를 사용한다.

대표적으로 React가 있다. React는 트리 형태의 Object를 통해 Virtual DOM을 구성하고 요소가 변경될 때 Virtual DOM을 업데이트한다. 그 후 최종 상태의 Virtual DOM을 실제 DOM에 그대로 반영하여 재배치와 다시 그리기를 최소화시켜 렌더링 최적화를 구현한다.

- 그 외 방법들

궁금하다면 여기서 확인해보자.

참고 자료


Naver D2: 브라우저는 어떻게 동작하는가?

'Web' 카테고리의 다른 글

[Web] HTTP란?  (0) 2019.10.15
[Web] CRP(Critical Rendering Path)와 최적화  (0) 2019.10.12
댓글