티스토리 뷰

📖  최근에 실무에서 진행하는 프로젝트의 리액트 마이그레이션을 위해 공부하고 있는데, 같은 가상돔이라는 개념을 쓰면서도 어떤 프레임워크(혹은 라이브러리)냐에 따라 접근 방식이 다를 수 있다는 것을 최근에 알게 되었다. 
이번 기회에 가상돔뿐만 아니라 React와 Vue의 가상돔 개념까지도 비교하면서 알아보도록 하자!

 

출처 : https://blog.10pines.com/2018/08/27/reactjs-virtual-dom/


브라우저의 렌더링 과정 (Critical Rendering Path)

브라우저가 화면을 렌더링하기 위해서는 다음과 같은 단계를 거치게 된다.

 

1. HTML 을 브라우저가 이해할 수 있도록 DOM(Document Object Model)이라는 일종의 객체(node) 로 변환한다.

2. CSS 를 브라우저가 이해할 수 있도록 CSSOM(CSS Object Model) 으로 변환한다.

3. 그리고 이 둘을 합쳐서 렌더 트리(Render Tree)를 만들게 된다. 이 것은 일종의 웹 페이지 청사진으로 이해할 수 있는데,
    요소들의 위치, 배치, 모양과 스타일에 대한 정보들이 담겨있기 때문이다.

4. 이후 레이아웃(Layout)의 단계를 거치는데, 렌더 트리에 포함되어 있는 요소들을 배치한다.

5. 그리고 실제로 화면을 그려낸다. (Painting)

 

JS 가 DOM을 수정하면 화면 업데이트가 발생하는데, 렌더링 되는 요소가 변경되면서 위 전체 과정을 다시 진행하게 된다.
문제는 이 때 Layout과 Painting은 오래 걸리는 과정이라는 것이다. (Reflow, Repaint 과정)
따라서 DOM 수정이 자주, 많이 일어나게 되면 성능이 현저히 떨어지게 된다.

이런 화면 한 번이라도 본 적 있으시죠?

 

 

화면 업데이트시 성능을 최적화하기 위해서는 DOM을 수정하는, 즉 DOM api를 호출하는 횟수를 절대적으로 줄이는게 필요하다

이를 위해서는 화면에 동시에 다양한 업데이트가 이루어질 때마다 DOM을 수정하는게 아니라, 업데이트들을 모은 후 한번에 수정할 수 있도록 신경써야한다. 하지만 서비스의 규모가 커질수록 발생하는 업데이트가 매우 많고 핸들링이 복잡해지기 때문에 이를 고려하는 것이 쉬운일은 아니다.

이를 도와주는 것이 바로 가상돔(Virtual DOM) 이라는 개념이다!

 

가상돔(Virtual DOM)

가상돔은 DOM을 자바스크립트 객체로 흉내내어(가상 표현, 가상 노드를 만든다고도 한다) 생성된 것인데, 이를 통해 실제 DOM 과의 비교하고, 업데이트가 필요한 곳만 적용하는 방식을 사용할 수 있다.

가상돔은 특정 기술이라기 보다는 패턴에 가까운 개념으로, 최초 개념은 리액트에서 개척되었는데, 리액트뿐만 아니라 vue를 비롯한 다른 프론트엔드 프레임워크에도 사용되어 성능 최적화를 돕고 있다.

 

React에서의 가상돔

  • 위에서 설명한 것과 같이 리액트는 렌더링할 때마다 전체 가상돔을 만들고 이전 가상돔과의 차이를 찾는다.
    • 차이가 있는 부분만 실제 DOM에 반영하고, 차이가 없으면 렌더링 요청이 있더라도 무시하는 방식으로 성능을 낸다. 즉, 최소한의 연산만으로 화면을 그린다.
    • 리액트 element를 가상돔으로 만들고 두 개의 dom 트리를 비교할 때 O(n^3)만큼의 계산 복잡도를 가지기 때문에 좀 더 효율적인 계산을 위해 재조정 알고리즘을 사용한다.
      • 비교 알고리즘 : root element 타입이 다를 경우, 이전 DOM 트리 노드들을 모두 버리고 트리 전체를 새로 구축한다.
      • 자식에 대한 재귀적 처리 : key 속성을 지원하여 자식들의 key 값이 다를 경우 변경점을 효율적으로 찾는다.
  •  동시에 발생한 업데이트들이 있다면 먼저 가상돔에 반영해놓고, 업데이트가 모였다면 한 번에 반영하여 DOM을 한 번만 수정할 수 있게 한다. 
    • 가상돔이 일종의 버퍼 역할을 해서 최소한의 횟수로 DOM을 업데이트 할 수 있도록 한다.

 

Vue에서의 가상돔

React 대부분의 다른 가상 DOM 구현은 순전히 런타임입니다.
조정(reconciliation) 알고리즘에 할당되는 가상 DOM 트리에 대해 어떠한 가정도 할 없으므로, 정확성을 보장하기 위해 트리를 완전히 탐색하고 모든 vnode props 비교해야 합니다.
또한 트리의 일부가 변경되지 않더라도 다시 렌더링할 때마다 항상 새로운 vnode 생성되어 불필요한 메모리 부하가 발생합니다.
이것은 가상 DOM 가장 비판적인 측면 하나입니다.
다소 무차별적인 조정 프로세스는 선언성과 정확성에 대한 대가로 효율성을 희생합니다.


  • vue 공식 문서에서는 위와 같이 다소 비판적(?)인 시선으로 리액트의 가상돔을 바라보고 있는듯 하며(ㅋㅋ), 리액트 방식과는 약간 차이가 있는 렌더링 메커니즘을 가진다.
  • vue의 가상돔 개념에서는 Compiler-Informed Virtual DOM (컴파일러에 알려진 가상 DOM) 이라는 또 다른 접근 방식을 설명한다.
  • 아래는 이런 접근 방식에 대한 내부 동작 특징들이다. 이러한 것들을 통해 리액트의 가상 DOM 보다 더 적은 비용으로 변경점만을 밀접하게 찾아내서 성능을 최적화할 수 있다는 모양이다.
    템플릿 언어를 지원함으로써 좀 더 차별화된 가상돔의 비교 알고리즘을 구현할 수 있다는 느낌이다.
    이런게 있다는 것 정도만 인지하고 우선 넘어가자.
    • 정적 호이스팅: Vue는 React와 달리 템플릿 언어를 지원한다. 이 템플릿은 가상 DOM의 렌더 함수로 컴파일 된다.
      템플릿에는 동적 바인딩이 포함되지 않는 경우가 많은데, 이런 정적 element를 포함하여 vnode를 생성해 비교하는 것은 불필요하다.
      따라서 비교를 건너뛸 수 있으며, 이러한 노드에 대해 정적 vnode로 압축할 수 있다. 
    • 패치 플래그 사용(https://github.com/vuejs/core/blob/main/packages/shared/src/patchFlags.ts)
    • Tree Flattening
// ** 정적 호이스팅 예제 **

<div>
  <div class="foo">foo</div>  <!-- 호이스트 됨 -->
  <div class="foo">foo</div>  <!-- 호이스트 됨 -->
  <div class="foo">foo</div>  <!-- 호이스트 됨 -->
  <div class="foo">foo</div>  <!-- 호이스트 됨 -->
  <div class="foo">foo</div>  <!-- 호이스트 됨 -->
  <div>{{ dynamic }}</div>
</div>

import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, createStaticVNode as _createStaticVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"

const _hoisted_1 = /*#__PURE__*/_createStaticVNode("<div class=\"foo\">foo</div><div class=\"foo\">foo</div><div class=\"foo\">foo</div><div class=\"foo\">foo</div><div class=\"foo\">foo</div>", 5)

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createElementBlock("div", null, [
    _hoisted_1,
    _createElementVNode("div", null, _toDisplayString(_ctx.dynamic), 1 /* TEXT */)
  ]))
}

// Check the console for the AST

 

 

 

 

참고한 도움이 된 자료

- https://ko.legacy.reactjs.org/docs/reconciliation.html

 

재조정 (Reconciliation) – React

A JavaScript library for building user interfaces

ko.legacy.reactjs.org

https://product.kyobobook.co.kr/detail/S000201352991

 

한 입 크기로 잘라 먹는 리액트 | 이정환 - 교보문고

한 입 크기로 잘라 먹는 리액트 | 자바스크립트 기초부터 애플리케이션 배포까지 처음 시작하기 딱 좋은 리액트 입문서이 책은 웹 개발에서 가장 많이 사용하는 프레임워크인 리액트 사용 방법

product.kyobobook.co.kr

https://ko.vuejs.org/guide/extras/rendering-mechanism#rendering-mechanism

 

Vue.js

Vue.js - The Progressive JavaScript Framework

vuejs.org

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
글 보관함