공부 및 일상기록

DOM과 Virtual DOM 본문

개발/React

DOM과 Virtual DOM

낚시하고싶어요 2023. 5. 3. 20:29

이번에는 DOM을 알아보고 Virtual DOM은 무엇인지 알아본 후 리액트에서 Virtual DOM을 사용하는 이유와 그로인한 결과를 알아보자

 

DOM (Document Object Model)

DOM(이하 돔으로 표기)은 웹페이지를 이루는 html, xml, svg 등의 문서를 객체로 표현하는 모델이다. 즉, 웹 페이지의 구조, 스타일, 콘텐츠 등을 객체로 표현하여, 자바스크립트와 같은 프로그래밍 언어로 제어할 수 있게 한다.

 

DOM의 주요 개념은 다음과 같다.

1. 노드 (Node)

돔에서 노드는 html 문서의 요소, 속성, 텍스트 등을 표현하는 객체이다. 노드는 각각 트리 형태로 연결되어 있으며, 부모-자식 관계를 가지고 있다. 돔에서는 모든 노드가 Node객체를 상속받으며, 이를 통해 다양한 노드 타입과 메서드를 사용할 수 있다.

 

2.요소 (Element)

돔에서 요소는 html문서의 태그를 표현하는 객체이다. 예를들어 <div>, <p>, <a>등이 요소이다. 요소는 각각의 속성과 하위 요소를 가지고 있다.

 

3. 속성 (Attribute)

돔에서 속성은 html문서의 태그 속성을 표현하는 객체이다. 예를들어 <a href="https://www.google.com">Google</a>에서 href속성은 속성객체이다. 속성은 요소의 프로퍼티처럼 작동하며, 자바스크립트를 사용하여 값을 변경할 수 있다.

 

4. 텍스트 (Text)

돔에서 텍스트는 html 문서의 텍스트를 표현하는 객체이다. 예를 들어, <p>Hello, World!</p>에서 Hello, World! 는 텍스트 객체이다.

 

5. 이벤트 (Event)

돔에서 이벤트는 사용자의 액션 (클릭, 스크롤 등)에 대한 응답으로 발생하는 객체이다. 예를 들어, 버튼을 클릭할 때 발생하는 클릭 이벤트는 onClick 이벤트 객체로 표현된다. 이벤트 객체는 자바스크립트를 사용하여 이벤트에 대한 응답을 처리할 수 있다.

 

돔은 웹페이지를 객체로 표현하여 자바스크립트와 같은 프로그래밍 언어로 제어할 수 있게 한다. 따라서 돔을 이해하고 활용하는 것은 웹 프로그래밍에서 필수적인 개념이다.

 

돔은 웹 브라우저에서 html, xml, svg문서를 읽어들여 객체 모델로 변환하여 만든다. 브라우저가 html 문서를 읽어들일 때, 브라우저는 문서의 각 요소를 노드로 변환하여 객체 모델로 구성한다. 돔은 브라우저에 내장된 자바스크립트 엔진과 함께 동작하며, 자바스크립트를 사용하여 돔 객체에 접근하고 조작할 수 있다.

 

VirtualDOM (이하 가상돔)

가상돔은 리액트와 같은 라이브러리나 프레임워크에서 사용되는 개념으로, 돔을 메모리에 가상으로 구현하는 방식이다. 가상돔은 돔과 구조가 동일하며, 각 요소의 태그, 속성, 텍스트 등을 객체로 나타낸다. 가상돔에서는 이러한 객체를 자바스크립트 객체로 구현하고, 이를 사용하여 웹페이지의 구조, 스타일, 컨텐츠 등을 조작한다. 이때, 가상돔은 실제 돔과 달리 메모리에서 작업을 처리하므로 브라우저에서 직접 돔을 조작하는 것보다 더 빠른 속도와 성능을 보장할 수 있다.

 

가상돔을 사용하는 라이브러리나 프레임워크에서는 먼저 가상돔을 생성하고, 이를 이용하여 화면을 렌더링 한다. 화면을 렌더링할 때, 변경된 부분만 실제 돔에 반영하여 불필요한 리소스 낭비를 방지한다. 이를 통해 웹페이지의 성능을 향상시키고 사용자 경험을 개선할 수 있다.

 

리액트에서 가상돔을 적용하는 큰 이유는 사용자 인터페이스를 더욱 빠르고 효율적으로 처리하기 위해서이다. 일반적으로 돔 조작은 브라우저의 성능에 영향을 미친다. 돔 조작이 많은 작업을 수행하는 경우 브라우저는 돔 조작으로 인한 렌더링 작업이 발생하여 느려지는 경우가 발생할 수 있다.

 

그러나 가상돔은 실제돔과 동일한 구조와 속성을 가지는 메모리상의 가상 객체로 리액트 컴포넌트에서 상태(state)나 속성(properties)이 변경될 때마다 리액트는 가상돔을 이용하여 변경된 부분만 업데이트 한다. 그리고 이렇게 변경된 부분만 실제 돔에 반영하여 변경된 내용만 화면에 다시 그려주는 방식으로 동작한다.

 

...!? 어차피 실제 DOM에 변경된 부분만 반영하는게 가능하다면 왜 Virtual DOM을 먼저 적용하고 실제 DOM에 적용할까..??

실제 돔에서 변경된 부분만 다시 그리는것이 불가능하지는 않다. 하지만 돔 조작이 일어날 때마다 브라우저는 렌더링 엔진을 다시 실행하여 돔트리와 렌더트리를 업데이트한다. 이때, 브라우저는 변경되지 않은 부분도 다시 그리게 된다.

 

이렇게 되면 불필요한 리소스 낭비를 하게 되고, 화면이 깜빡이는 등의 불필요한 효과가 발생할 수 있다. 또한 변경된 부분을 찾아내기 위해 돔트리를 전부 순회해야 하는데 이는 비용이 매우 많이 드는 작업이다.

 

그렇다면 가상돔은 어떻게 빠르게 변경된 곳만 찾아낼까?

그 이유는 가상돔은 메모리상에서만 동작하기 때문이다. 가상돔은 실제 돔과 동일한 구조와 속성을 가지는 메모리상의 가상 객체를 사용하므로, 변경된 부분을 쉽게 탐지할 수 있다. 하지만 실제 돔은 브라우저에 의해 관리되는 복잡한 구조를 가지고 있다. 돔트리를 탐색하면서 변경된 부분을 찾아내고, 이를 처리하는것은 매우 복잡하고 또한 브라우저마다 돔의 구조와 기능이 약간씩 다르기 때문에 이를 처리하는 코드를 작성할 때 크로스 브라우저 호환성을 고려해야 하므로 구현이 어렵다.

 

음.. 그럼 가상돔이 실제 돔에 반영될때는 어떻게 반영되는거지..?

가상돔이 실제 돔에 반영될 때는 모든 노드를 다시 그리지 않고 변경된 부분만 다시 그리게 된다.

가상돔에서는 실제 돔에 변경된 부분만을 반영하기 위해 먼저 변경이전 가상돔과 변경후 가상돔을 비교 하고 변경 부분을 탐지한다. 이때 이전 가상돔과 새로운 가상돔 사이의 차이(diff)를 찾아내는 알고리즘을 사용하여 효율적으로 계산하게 된다.

 

이렇게 변경된 부분을 계산하고 실제 돔에 반영하는 작업은 실제 돔의 업데이트를 최소화 하기 위해 몇가지 최적화 기법을 사용한다.

1. Batch Update : 가상돔에서 변경된 부분을 일괄 업데이트 한다. 즉, 모든 변경된 부분을 한 번에 처리하고, 실제 돔에 한번만 업데이트 한다.

2. DOM diffing : 변경된 부분만을 실제 돔에 반영하기 위해, 가상 DOM과 실제 DOM의 차이(diff)를 찾아낸다. 이후, 차이를 이용하여 변경된 부분만을 업데이트 한다.

3. DOM reuse : 가상 DOM에서 생성된 실제 DOM 노드를 재사용한다. 즉, 새로운 노드를 사용하는 대신, 기존의 노드를 재사용하여 성능을 향상시킨다.

 


그렇다면 구구절절한 긴 글을 함축적으로 요약해서 보자

 

리액트는 가상돔을 이용해 실제 돔을 조작하는데 걸리는 시간을 획기적으로 줄인다.

 

만약 실제 돔에서 텍스트 컬러를 바꾸고 싶다면?

1. 브라우저가 html을 탐색해 해당 element를 찾고

2. 해당 element와 자식 element를 돔에서 제거하고

3. 새롭게 수정된 element로 교체하고 (바뀐 컬러가 담긴 element)

4. CSS를 다시 계산하여 바뀐 컬러가 적용된다.

 

이 작업을 반복하게 브라우저는 매우 느려진다.

 

하지만 리액트는 어떻게 하느냐?

리액트는 두개의 가상돔 객체를 가지고 있다. 하나는 실제 돔과 같은가상돔(변경이전), 하나는 변경된 가상돔(변경후)

왼쪽은 변경이전 가상돔, 가운데는 변경후 가상돔, 오른쪽은 변경점을 업데이트 한 실제 돔

리액트는 state가 변경될 때마다 리렌더링을 하게 된다. 렌더링 이전의 화면 내용을 담고 있는 첫번째 가상돔과 변경 후 두번째 가상돔을 비교해 어떤 element가 변했는지 비교한다. 이 과정이 Diffing 이다.

 

그리고 해당 차이(diff)를 실제 돔에 반영하게 된다. 이 전반적인 과정을 Reconciliation(재조정)이라고 한다. 이 과정이 효율적인 이유는 Batch Update 때문이다. 이는 변경된 element들을 집단화 시켜 한번에 실제 돔에 적용하는 방식이다.

 

만약 리스트에 10개의 항목이 바뀌었다면, 실제돔을 10번 반복 수정하는것이 아닌, 한번에 10개를 적용시키는 것이다.

 

DOM조작에서 비용이 가장 많이 발생하는 지점이 브라우저에 화면을 그려주는 작업인 만큼, Batch Update는 매우 효율적인 최적화 기법이다.

 

만약 상태가 변경되어도, 실제 화면에서 변경점이 없다면 리액트는 이를 렌더링 하지 않고, 이전에 렌더링한 결과를 유지한다. 이를 Dirty Checking이라고 한다.