미분류/Tip

브라우저의 렌더링 과정, 렌더큐와 리플로우/리페인팅, Virtual DOM

DarrenKwonDev 2021. 5. 20. 01:09

브라우저는 어떻게 구성되어 있는가

 

사용자 인터페이스(UI) 레이어는 브라우저에서 볼 수 있는 거의 모든 것으로, 요청한 페이지를 보여주는 창 외의 모든 UI를 의미합니다. 주소창, 뒤로가기, 앞으로 가기, 새로고침, 북마크, 환경설정과 같은 UI가 있습니다. 일종의 '틀'

브라우저 엔진은 사용자 인터페이스와 렌더링 엔진 사이에서 중재자 역할을 합니다. 만약 여러분들이 사용자 인터페이스 레이어에 있는 새로고침 버튼을 눌렀다면, 브라우저 엔진은 이를 이해하고 새로고침 명령을 수행합니다.

렌더링 엔진은 HTML과 CSS, JavaScript를 파싱하고 그 결과물을 바탕으로 페이지를 그려내는 역할을 합니다. 각 브라우저는 다양한 엔진을 사용하는데, Chrome과 Opera, Edge는 Blink를, Firefox는 Gecko를, Internet Explorer는 Trident를, Safari는 WebKit을 사용합니다.

네트워크 레이어는 HTTP나 HTTPS 같은 프로토콜을 이용해 외부의 리소스를 얻어오고, 서버에 요청을 보낼 때 사용되는 레이어입니다.

JavaScript 인터프리터(해석기) 는 JavaScript를 해석하고 실행하는 역할을 합니다. 가장 유명한 엔진으로 Chrome에 탑재된 구글의 V8이 있습니다.

UI 백엔드는 브라우저가 동작하고 있는 운영체제의 인터페이스를 따르는 UI들을 처리합니다. 얼럿(alert)이나 셀렉트 박스(select)가 운영체제 별로 다르게 동작하는 것을 쉽게 확인할 수 있죠.

자료 저장소는 브라우저 자체에서 하드디스크와 같이 데이터를 로컬에 저장하기 위한 레이어로, 쿠키나 로컬 스토리지, 세션 스토리지, indexedDB, 웹 SQL, 파일시스템 등에 접근하고 데이터를 저장하는데 사용됩니다.


렌더링 엔진의 동작하는 과정 = 중요 렌더링 경로(Critical Rendering Path) = HTML/CSS/JS 파싱 및 그려내기



파싱(Parsing) => 렌더 트리(Render Tree) 구축 => 레이아웃(Layout) 또는 리플로우(Reflow) => 페인트(Paint)


요약하자면, 파싱한 다음에 HTML/CSS를 통해 렌더 트리를 만들고

1. 파싱

렌더링 엔진에서는 HTML과 CSS를 파싱합니다.
파싱 과정에서 \<link\>나 \<script\>를 만나면 파싱을 일시 중지하고 해당 내용을 분석합니다.
때문에 script 태그를 가급적 body의 하단부에 위치시키라는 이유가 여기에 있는거죠.

HTML/CSS와 다르게 JS는 JS 인터프리터에서 파싱됩니다.

2. 렌더 트리 구축 = DOM 트리 + CSSOM 트리

파싱된 HTML를 가지고 파스 트리(parse tree)를 만듭니다.
참고로, 파스 트리는 토큰화된 문자열을 단순하게 구조화한 트리이고, DOM 트리는 아닙니다.
파스 트리를 가지고 다시 DOM 트리를 구성하게 됩니다.

과정이 진행되는 도중 파싱된 CSS를 이용해서도 CSSOM 트리도 만들기 시작합니다.

DOM 트리 + CSSOM 트리 = 렌더 트리를 구성하게 됩니다.

 

3. 플로우, 레이아웃


요소를 배치하는 작업입니다.
겍코 렌더링 엔진은 플로우, 웹킷은 레이아웃이라고 부릅니다.
이 플로우 작업을 다시하게 되는 것을 '리플로우'라고 합니다.

4. 페인팅


말 그대로 페인팅입니다. 배치된 엘리먼트에 색을 입히는 등 꾸밈 작업을 수행합니다.

리플로우/리페인트


브라우저를 사람이라고 생각해봅시다.
지어 놓은 건물 부수고 다시 측량하라고 하면 힘들고(리플로우), 다시 인테리어(리페인트)하라고 하면 힘듭니다.
가급적 이런 일은 필요하지 않으면 안하는게 좋겠지만, 괜찮아 보이는 웹을 만들려면 리플로우/리페인트 둘 다 일어납니다.
솔직히 말해서, 리플로우를 안 일어나게 작성하면 웹페이지가 너무 밋밋하고, 인터렉션 자체가 없어집니다.
언제 일어나는지는 알아두고, 오용하는 것을 막는 정도로 타협을 봐야겠죠.

그렇다면 언제 리플로우가 일어나는가?


아래 함수가 트리거 되면 특정 돔의 width가 600px로 재조정됩니다.

function reflow() { document.getElementById('bad-dom').style.width = '600px'; }


리플로우는 다음과 같은 경우에 발생합니다.
외우기보다, 상식적으로 "아, 브라우저가 다시 DOM을 그려야겠구나"라는 생각이 들면 그겁니다.

  • DOM 추가, 삭제
  • DOM의 위치, 크기, 패딩, 마진 등 기하적인 속성의 변경 (hover 스타일성애자들이 주로 씀)
  • 폰트 변경, 이미지 변경
  • window.resize 이벤트시 영향 받는 여러 DOM들
  • 애니메이션 (DOM 지우고, 옮긴 좌표에 새로 그리고의 반복이니까)

 

리페인트는 언제 일어나는가?


우선, 리플로우가 일어나면 자연스레 리페인트도 다시 일어나게 됩니다.
화면 전체의 가시성을 모두 확인해야 해서 값비싸다고 하다는데
그러나, 리플로우 없이도 리페인트가 발생할 때가 있는데 가시성과 관련된 css 속성이 변화할 때 일어납니다.
대표적으로 opacity, background-color, visibility, outline이 있겠습니다.



그러면 어떻게 해야 함?


* 리페인트보다 리플로우가 훨씬 값비싼 동작이라고 합니다. 우선 리플로우를 줄입시다.


1. visibility, display, opacity에 대해
visibility는 화면에 안 보이는 것일 뿐, 이미 위치를 차지하고 있다. 따라서 visibility가 변경되면 리플로우가 일어나게 된다.
display가 none이면 화면 자체에 공간을 차지 하지 않으므로 리플로우를 줄일 수 있습니다.만약 단순히 보이지 않게 만들고 싶다면 opacity를 쓰면 리플로우없이 리페인트만 발생합니다.

2. 애니메이션

애니메이션은 DOM을 지우고, 옮기고의 반복이니 리플로우겠죠.
애니메이션이 발생하는 DOM은 position을 fixed, absolute로 설정하는게 좋습니다. 다른 DOM에 영향을 안 미치니까 리플로우는 안 일어나겠죠.

3. javascript로 css 속성을 많이 변경할 때는 cssText를 사용할 것

// 3번의 리플로우 el.style.padding = '8px'; el.style.width = '320px'; el.style.height = '240px'; // 1번의 리플로우 el.style.cssText = 'padding: 8px; width: 320px; height: 240px;'; [출처] - https://wonism.github.io/reflow-repaint/

 

Virtual DOM은 왜 빠른 것인가

브라우저의 렌더링 과정 중에서 가장 많은 비용을 소요하는 작업은 레이아웃(플로우)과 페인팅작업입니다.
이 과정은 줄여야 웹이 빨라집니다.

js로 DOM을 직접 조작하여 수정을 할 경우, 이 레이아웃과 페인팅 작업을 다시하게 됩니다.
한 두개의 DOM을 조작하는 것은 빠를테지만, 이런 조작이 for 문을 돌면서 100개가 이루어진다고 보면, 레이아웃과 페인팅 작업을 100번 해야 하는 겁니다. 연산의 횟수가 많아진다는 거죠. 따라서, 많은 양의 DOM을 직접 조작하는 것은 많은 비용을 초래하게 됩니다.

반면 가상 DOM은 실제로 렌더링되지는 않았지만, 실제 DOM 구조를 반영한 상태로 메모리에 있는 가상의 DOM입니다. 메모리 상에 있고, 실제 화면에 그려야할 필요는 없기 때문에 실제 DOM보다는 연산 비용이 적습니다. 가상 DOM은 이러한 특징을 바탕으로 위에서 말한 변경 사항들을 한 번에 묶어서 실제 DOM에 반영을 합니다. 물론 레이아웃 단계와 페인트 단계에서 한 번에 변경되어야 하는 사항은 많아집니다. 대신 단 한 번의 계산만으로도 바뀐 DOM을 적용할 수 있기 때문에 연산의 횟수는 최소한이 됩니다.

결국, Virtual DOM은 레이아웃(리플로우)와 페인팅 작업을 최소화 할 수 있도록 한 번에 조작을 가하기 때문에 직접 DOM을 조작하는 것보다 적은 리소스를 사용하면서 수정할 수 있단든 점에서 빠르다고 하는 겁니다.




reference)

www.youtube.com/watch?v=BYbgopx44vo
https://wonism.github.io/reflow-repaint/
d2.naver.com/helloworld/59361
wormwlrm.github.io/2021/03/27/How-browsers-work.html
velog.io/@yejineee/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%8F%99%EC%9E%91-%EA%B3%BC%EC%A0%95