안녕하세요. IT 엘도라도 에 오신 것을 환영합니다.
글을 쓰는 것은 귀찮지만 다시 찾아보는 것은 더 귀찮습니다.
완전한 나만의 것으로 만들기 위해 지식을 차곡차곡 저장해 보아요.   포스팅 둘러보기 ▼

리액트 (React)

[React] Virtual DOM이란? (+ 브라우저 렌더링 과정, Reflow, Repaint)

피그브라더 2020. 7. 24. 09:54

1. 브라우저 렌더링 과정

[Figure] Webkit 엔진의 렌더링 프로세스

 

1-1. DOM 트리 생성

HTML 파서가 전달받은 HTML 파일에 담겨 있는 HTML 코드들을 파싱 하여 메모리 상에 DOM 객체들로 이뤄진 DOM 트리를 생성한다. DOM(Document Object Model)은 문서의 각 요소를 객체(Object)로 표현하는 방법이자 모델을 뜻한다. 이러한 DOM 트리의 구축으로 인해 스크립트 언어가 문서의 뷰를 편하게 조작할 수 있다.

 

1-2. 스타일 규칙 생성

CSS 파서가 전달받은 HTML 파일과 CSS 파일에 담겨 있는 CSS 코드들을 파싱 하여 메모리 상에 스타일 규칙들을 생성한다.

 

1-3. 렌더 트리 생성

앞서 생성한 DOM 트리와 스타일 규칙들의 정보를 바탕으로, 실제로 브라우저의 화면에 노출되어야 하는 노드들에 대한 정보인 렌더 트리를 생성한다. 참고로 '실제로 브라우저의 화면에 노출'된다는 것의 의미는, <head> 태그 혹은 display 속성이 none인 태그들과 같이 눈에 보이지 않는 노드들은 렌더 트리를 생성할 때 제외한다는 것을 의미한다.

 

1-4. 레이아웃 (→ 리플로우)

렌더 트리의 각 노드가 화면의 어느 위치에 어떤 크기로 배치되어야 하는지에 대한 정보를 계산하는 단계이다.

 

1-5. 페인트 (→ 리페인트)

렌더 트리의 각 노드를 실제로 브라우저의 화면에 그리는 단계이다.

 

2. DOM 노드 조작 시 : 리플로우 (Reflow), 리페인트 (Repaint)

문서를 DOM 트리로 표현한 덕분에, JavaScript와 같은 스크립트 언어로 문서의 각 요소를 조작할 수 있게 되었다. 그런데 사실 스크립트 언어로 특정 DOM 노드에 해당하는 객체에 접근하여 CRUD 작업을 수행하는 것은 가벼운 연산이 아니다. 하나의 DOM 노드가 조작될 때마다 DOM 트리와 스타일 규칙들이 수정되므로 렌더 트리를 다시 생성해야 하고, 그 렌더 트리를 대상으로 레이아웃 단계와 페인트 단계를 다시 거쳐야 하기 때문이다. 레이아웃 단계를 다시 거치는 것을 리플로우(Reflow)라고 하며, 페인트 단계를 다시 거치는 것을 리페인트(Repaint)라고 한다. 그런데 레이아웃 단계와 페인트 단계는 꽤나 오버헤드가 큰 작업이다. 물론 레이아웃에 영향을 미치지 않는 선에서 CRUD 작업을 수행한다면(예를 들어 색상만 바꾼다든지) 리플로우는 수행하지 않을 것이지만 여전히 리페인트는 수행한다. 이러한 문제점을 해결하기 위해 등장한 것이 바로 Virtual DOM이다.

var style = document.body.style;
style.padding = '20px';  // reflow, repaint
style.border = '10px solid red';  // reflow, repaint
style.color = 'blue';  // repaint
style.backgroundColor = '#ffa';  // repaint
style.fontSize = '1em';  // reflow, repaint

document.body.appendChild(document.createTextNode('hello world'));  // reflow, repaint

 

3. Virtual DOM (feat. React)

앞서 말했듯 DOM 노드를 조작하는 작업은 동적인 UI를 구성하는 것에 적합하지 않다. DOM 노드 하나를 조작할 때마다 리플로우나 리페인트 작업이 수행되면서 브라우저의 성능 저하를 유발하기 때문이다. 이러한 문제점을 해결하기 위해 Virtual DOM이 등장하게 되었다. Virtual DOM은 실제 DOM을 모방하는 형태로 메모리 상에서만 존재하는 가상의 DOM을 의미한다. 실제로 화면에 렌더링 하는 과정을 거치지 않고 메모리 상에서만 그려지는 DOM이기 때문에 훨씬 오버헤드가 작다는 특징이 있다. 이러한 Virutal DOM을 활용하면 문서의 각 요소를 훨씬 더 효율적인 방식으로 동적 제어가 가능해진다. 이를 채택한 대표적인 JavaScript 라이브러리가 React이다.

 

React는 문서의 특정 부분이 리렌더링 되어야 할 때 그 부분에 해당하는 Virtual DOM 트리를 메모리에 새로 생성한다. 그리고 이전에 존재하던 Virtual DOM 트리와 O(n)의 휴리스틱 알고리즘으로 비교하여 차이점을 파악한다. 그리고 그 차이점들을 하나로 모아서 실제 DOM에게 전달해준다. 이로 인해 실제 DOM의 리렌더링 연산(리플로우, 리페인트)은 단 한 번만 일어나게 되어, 큰 성능의 이득을 얻게 된다(Batch Update). 물론 React는 JavaScript 라이브러리이기 때문에, React가 할 수 있는 건 바닐라 JavaScript로도 할 수 있다. 즉 바닐라 JavaScript로 실제 DOM을 조작할 때도 DOM fragment를 잘 활용하면 여러 차이점들을 하나로 모아서 딱 한 번의 리렌더링 연산만 수행하는 것이 가능하다. 그러나 이를 위해서는 매번 어떤 DOM 노드가 변경되어야 하고 어떤 DOM 노드는 변경될 필요가 없는지 등을 파악할 수 있어야 하고, 이는 복잡한 과정이기 때문에 실수가 발생할 가능성도 커진다. React의 Virtual DOM은 이러한 복잡한 과정들을 자동화 및 추상화해준다는 점에서 의미가 있다고 할 수 있다.

 

 

 

 

 

본 글은 아래 링크의 내용을 참고하여 학습한 내용을 나름대로 정리한 글임을 밝힙니다.

https://programmingwithmosh.com/react/react-virtual-dom-explained/

http://blog.drakejin.me/React-VirtualDOM-And-Repaint-Reflow/

https://velopert.com/3236