React와 가상 DOM 그리고 Svelte..

Jiwoo JEONG·2022년 8월 19일
0
post-thumbnail

React의 동작

브라우저의 동작

1. HTML을 parsing(분석)하여 DOM(Document Object Model)을 구성하여 
   각 DOM node로 DOM tree를 구성한다.
    1-1. style을 만나면 CSS를 parsing하여 CSSOM(CSS Object Model)을 구성하여 
    	 각 CSSOM node로 CSSOM tree를 구성한다.
    1-2. script를 만나면 Javascript를 가져온다
2. 1을 통해서 만들어진 DOM tree와 CSSOM tree를 통하여 Render tree를 구성한다.
3. Layout/Reflow : Render tree에서 요소들의 정확한 위치와 크기를 계산한다.
4. Paint : Render tree를 화면의 픽셀로 변환한다. 
		   위치, 크기와 관계 없는 CSS를 적용한다
          

  • DOM: HTML을 Javascript와 브라우저가 읽을 수 있도록 분석하여 나온 객체 모델
  • CSSOM : CSS를 분석하여 나온 객체 모델
  • Render tree 구성
    1. visibility:hidden은 Layout 시 공간을 차지한다.
    2. display:none은 Render tree 구성 시에 포함되지 않는다.

DOM 제어 : 웹을 동적으로 제어한다

➡️ HTML 요소들을 동적으로 제어한다
➡️ DOM API로 DOM 요소들을 CRUD(Create, Retrieve, Update, Delete) 한다

jQuery

👎: jQuery는 실제 DOM을 제어하기 때문에 interactive UI가 많은 최근의 웹 어플리케이션에서는 HTML ➡️ DOM 구성 ➡️ DOM tree 구성 ➡️ Layout ➡️ Paint가 매번 이루어지기 때문에 연산이 많아진다. 이는 브라우저 성능 저하의 원인이 된다. 그래서 가상 DOM을 사용하는 React, Vue와 같은 프레임워크의 등장과 함께 jQuery를 사용할 이유가 줄어들었다.

가상 DOM

  • React를 기준으로 작성하였습니다.

render()

React의 render()는 React Element tree를 만드는 함수이다.
➡️ state나 props가 변하면 새로운 element tree를 return
➡️ 어떻게 효과적으로 가상 DOM을 사용하였나?

Diffing Algorithm

➡️ old element treenew element tree를 비교하여 바뀐 element만 new element로 갱신한다.
➡️ 재조정(Reconciliation)은 element의 root부터 비교한다.
➡️ 비교는 실제 DOM과 가상 DOM을 동시에 순회하며 진행된다.

Element의 type이 다른 경우 (HTML Tag가 다른 경우)

➡️ old element tree는 버리고 new element tree로 바꾼다. 그 말은 즉슨, parent의 element type이 달라지면 children도 버려지고 children도 new element tree로 바뀌며 state와 props도 모두 버려진다. re-rendering이 발생한다.

Element의 type이 같은 경우 (HTML Tag가 같은 경우)

➡️ 동일한 것들은 유지한다. 다만 바뀐 속성만 갱신한다. 그리고 children을 재귀처리한다.

children 재귀처리

#old element
<ul>
  <li>first</li>
  <li>second</li>
</ul>
#new element
<ul>
  <li>first</li>
  <li>second</li>
  <li>third</li>
</ul>

이 경우에는 맨 마지막에 new element인 <li>third</li>가 추가되는 것이라 문제가 없다. 하지만

#old element
<ul>
  <li>Duke</li>
  <li>Villanova</li>
</ul>
#new element
<ul>
  <li>Connecticut</li>
  <li>Duke</li>
  <li>Villanova</li>
</ul>

위 예제에서는 동시 순회하며 비교할 때 <li>Duke</li><li>Connecticut</li>의 children이 달라서 li element의 children을 모두 new element로 갱신해 버릴 것이다. 지금의 예제에서는 depth가 낮아서 text만 변경될 것이지만 depth가 깊은 children element라면 바뀌지 않아도 될 것들이 갱신되어 성능적으로 안좋은 결과를 가져올 수 있다. 이 때문에 React에서는 key 속성을 확인한다.

key 속성

key 속성이 있다면 key를 통해 old elementnew element의 자식이 일치하는지 확인한다. 따라서 key 값은 고유한 값이어야 한다.
❌주의사항❌ : key를 array의 index로 사용하게 되면 array가 재정렬되는 경우에 key값도 변경된다. old elementnew element의 key 값이 같은데 new element의 children이 달라서 새로운 것으로 갱신하였지만 이것이 의도한 것과 다를 수 있다. 재정렬되지 않는 경우에는 큰 문제가 발생하지 않을 것.

그래서 React에서는

그래서 React에서는 render()를 호출하면 모든 element를 Diffing Algorithm으로 비교가 일어난다. 변화한 것이 없으면 같은 값을 반환한다.

Svelte

하지만 Svelte는 이러한 가상 DOM을 사용하지 않고 실제 DOM에 접근한다.
Svelte Blog에서는 다음과 같이 이야기한다.

가상 DOM이 항상 빠르다라는 것은 실제 DOM에 대한 접근 보다는 브라우저 관점에서 성능적으로 
빠를 수 있다.
가상 DOM이 항상 빠르다는 것은 React가 발표될 당시 2013년에 성능이 좋지 않은 프레임워크와의
비교, 혹은 아무도 시도하지 않을 일에 대한 비교이다.
가상 DOM을 사용하기 위해서는 항상 실제 DOM과 가상 DOM을 생성해야하며, 비교하는 과정에서 
overhead가 발생할 수 있다.

Svelte가 어떻게 동작하는지 정확하게는 모르지만 브라우저 관점에서 어떤 것이 더 나은가 생각해볼 필요가 있다.

Reference

Vanilla Javascript로 가상돔(VirtualDOM) 만들기-개발자 황준일
React 공식문서 - Reconciliation
React가 태어난 배경 - junoflog
Virtual DOM is pure overhead - Svelte blog

profile
FE Developer as Efficiency Maker

0개의 댓글