Frontend Engineer - 박준형

Published on

Virtual Dom Deep dive

Authors
  • Name
    Twitter

Virtual Dom은 무엇인가?

React와 같은 자바스크립트 라이브러리에서 사용 되는 개념인 Virtual DOM(가상돔)은 실제 DOM(Document Object Model)과 비슷한 구조를 가지지만, 자바스크립트 엔진 메모리에 상주하며 브라우저에서 실제로 표시되는 돔과는 독립적으로 존재합니다.

가상돔이 존재하는 자바스크립트 엔진의 메모리는 브라우저의 렌더링 엔진이 동작하는 곳과는 별개의 공간이다. 브라우저는 자바스크립트 엔진과 렌더링 엔진을 분리하여 동작하며, 자바스크립트 엔진은 가상돔을 비롯한 자바스크립트 객체들을 처리하고 렌더링 엔진은 HTML CSS 이미지 등을 처리한다.

가상돔은 자바스크립트의 일반 객체로 이루어져 있으며, 뷰(View)를 업데이트하는 데 사용된다. 일반적으로 브라우저에서 실제로 표시되는 돔은 매우 복잡하고 대규모일 수 있다. 이러한 돔 구조를 변경하면 브라우저가 렌더링하는데 많은 시간이 걸릴 수 있다. 이는 병목현상을 야기할 수도 있으며 많은 조작이 이루어질 경우 성능 저하를 초래할 수 있다. 이러한 문제를 해결하기 위해 리액트와 같은 라이브러리는 가상돔을 사용하여 돔 조작을 최소화하고 성능을 개선한다.

가상돔은 위의 문제를 해결하기 위해 사용된다. 브라우저에서 표시되는 실제 돔과 동기화 되지는 않는다. 대신 업데이트된 가상돔을 사용하여 이전 가상돔과 비교하여 변경된 부분만 실제 돔에 적용한다.

이를 통해 브라우저에서 필요한 최소한의 업데이트만 수행하여 성능을 개선하게된다.

💡 가상돔 역시도 자원을 소비하기에 가상돔의 업데이트 또한 최소화해야한다. 이를 위해 리액트와 같은 라이브러리는 변경되는 부분만 업데이트하고 불필요한 렌더링을 방지하여 성능을 최적화한다.

리액트는 가상돔을 사용함으로써 UI를 빠르게 업데이트 할 수 있도록 도와준다.

이를 통해 개발자는 UI 업데이트 로직을 직접 작성하는 대신에 리액트라는 라이브러리에게 위임하므로 생산성을 높일 수 있다. 또한 가상돔은 리얼돔과는 별개의 메모리 공간에서 작동하므로 UI 업데이트 작업이 빠르고 효율적으로 처리 될 수 있다.

성능향상

UI를 업데이트하는 방법에는 여러가지 방법이 있다.

가장 간단한 방법으로는 UI 전체를 새로 렌더링하는 방법이다. 하지만 이 방법은 UI의 크기가 커질수록 렌더링 시간이 길어지는 문제가 있고 변경되지 않아도 되는 부분까지 모두 리렌더링이 필요하므로 불필요한 작업이 많아진다.

React에서는 가상돔Diffing 알고리즘을 사용하여 변경된 부분만 실제 돔에 업데이트 함으로써 성능을 향상시킨다. 가상돔과 리얼돔은 동일한 구조를 갖지만, 메모리 상에 존재하므로 실제 돔보다 빠른속도로 UI업데이트 작업을 처리할 수 있다.

Diffing 알고리즘

Diffing 알고리즘은 이전 가상돔과 새로운 가상돔을 비교하여 변경된 부분을 찾아내는 과정이다. 이전 가상돔과 새로운 가상돔은 각각 하나의 트리 구조로 표현되며, 이 트리 구조를 비교하여 노드 단위로 변경된 부분을 탐색한다.

노드의 타입이나 속성, 자식 노드 등을 비교하여 변경된 부분을 탐색한다. 노드의 타입이나 속성이 변경된 경우 해당 노드를 업데이트하고 자식 노드가 변경된 경우 해당 노드의 자식 노드를 비교하여 변경된 부분을 찾아낸다.

Diffing 알고리즘의 구체적인 동작 방식은 아래와 같다.

  1. 트리 순회 이전 가상돔과 새로운 가상돔을 순회하면서 각 노드의 타입과 속성을 비교한다. 이를 위해 가상돔은 트리구조로 이루어져 있으며 깊이 우선 방식으로 순회한다.
  2. 변경 여부 확인 각 노드의 타입과 속성을 비교한 후 이전 가상돔과 새로운 가상돔이 동일한 노드인지 비교한다. 노드가 동일할 경우 변경되지않았다고 판단한 후 다음 노드로 이동한다.
  3. 노드 추가/제거 동일한 노드가 아닐 경우 해당 노드를 추가하거나 제거한다. 추가하는경우 새로운 노드를 생성하고 제거하는 경우 이전 노드를 제거한다.
  4. 속성 업데이트 노드가 동일하지만 속성이 변경된 경우 속성을 업데이트한다. 이전 속성과 새로운 속성 값을 비교하여 변경된 속성만 업데이트하고 변경되지 않은 속성은 그대로 유지한다.
  5. 자식 노드 순회 자식 노드가 있는 경우 이전 가상돔과 새로운 가상돔의 노드를 순회하며 Diffing 알고리즘을 재귀적으로 적용한다. 이 과정에서 변경된 부분이 있다면 해당 노드를 업데이트하고 변경되지 않은 부분은 그대로 유지한다.

Reconciliation 알고리즘

Reconciliation 알고리즘은 Diffing 알고리즘으로 찾아낸 변경된 부분을 실제 돔에 반영하는 과정이다. 변경된 부분이 많은 경우에는 모든 변경사항을 적용하는 것이 아니라, 변경된 부분만 최소한의 작업으로 처리하여 성능을 향상시킨다.

변경된 부분을 실제 돔에 적용하기 위해 변경된 노드를 다시 그려야 하는 경우와 기존 노드를 업데이트하는 경우로 나눌 수 있다. 기존 노드를 업데이트 하는 경우에는 변경된 속성값이나 자식 노드를 새로운 값으로 갱신한다.

Reconciliation 알고리즘의 구체적인 동작 방식은 아래와 같다.

  1. 노드 추가/제거 Diffing 알고리즘에서 추가되거나 제거된 노드가 있다면, 해당 노드를 리얼돔에 추가하거나 제거한다. 추가되는 경우 리얼돔에 새로운 노드를 생성하고 제거되는 경우 해당 노드를 제거하고 새로운 위치에 새로운 노드를 생성한다.
  2. 노드이동 노드의 위치가 변경된 경우, 해당 노드를 새로운 위치에 추가한다. 이를 위해 리얼돔에서 해당 노드를 제거하고 새로운 위치에 새로운 노드를 생성한다
  3. 속성업데이트 Diffing 알고리즘에서 속성이 변경된 노드가 있다면 해당 노드의 속성을 업데이트한다. 이를 위해 리얼돔에서 해당 노드의 속성을 업데이트한다.
  4. 자식노드 순회 자식 노드가 있는 경우 이전 가상돔과 새로운 가상돔의 자식 노드를 순회하면서 Reconciliation 알고리즘을 재귀적으로 적용한다. 이 과정에서 변경된 부분이 있다면 해당 노드를 업데이트하고 변경되지 않은 부분은 그대로 유지한다.