본문 바로가기

프로그래밍 - 활용/Front-end

리액트의 Virtual DOM 동작 원리 분석기: Fiber Reconciler편

1. DOM이란?

브라우저가 웹페이지의 콘텐츠와 구조를 어떻게 보여줄 것인가에 대한 정보를 담고 있는 것이다.

웹페이지에서 DOM이 생성되어 사용자에게 보이는 과정은 다음과 같다.

1. HTML 파싱 > DOM 노드로 구성된 트리(DOM) 생성
2. CSS 다운로드
3. CSS 파싱 > CSS 노드로 구성된 트리(CSSOM) 생성
4. DOM에 CSSOM 적용

 

2. 가상 DOM(Virtaul DOM)이란?

(1) 정의

리액트가 관리하는 가상의 DOM이다.

웹페이지가 표시해야 할 DOM을 메모리에 저장하고, 리액트가 변경에 대한 준비가 완료되면 실제 브라우저의 DOM에 반영하는 로직을 바탕으로 동작한다. 이때 DOM 계산을 브라우저가 아닌 메모리에서 진행해, 실제 렌더링 과정을 최소화하는 것이 핵심이다.

 

(2) 탄생한 이유

브라우저가 웹페이지를 렌더링하는 것은 복잡하고 많은 비용이 발생한다. SPA(Single Page Application)의 경우, 하나의 페이지에서 라우터를 통해 데이터 변경을 보여줘야 하기에 DOM 관리에 부담해야 할 비용이 크다. 개발자가 DOM을 수동으로 하나씩 변경한다면, 복잡한 애플리케이션일수록 변경된 값과 관련된 값을 파악하는 것이 어려워지게 된다.

Virtual DOM을 사용하게 된다면 리액트 내부의 파이버와 재조정자가 내부적 알고리즘을 통해 값을 관리하여, 대규모 웹앱을 효율적으로 유지보수 및 관리가 가능해지게 된다.

 

값으로 UI를 표현할 수 있다는 것이 중점이다. 화면에 표시되는 UI를 파이버와 파이버 재조정자를 통해 자바스크립트 값으로 관리하게 된다. (브라우저의 DOM을 빠르게 그리고 반영하는 것이 중점이 되지 않는다.)

 

(3) 동작

실제 DOM과 가상 DOM을 비교해 변경 사항을 수집하고, 변경 관련 정보를 가진 파이버를 기준으로 화면에 렌더링을 요청하게 된다. 과거엔 Stack 재조정자를 통해 동기적으로 진행했으나, 현재엔 파이버 재조정자를 통해 비동기적으로 진행한다.

 

  • React 내부 동작 단계
1. 렌더(Render)
일반 객체인 React 엘리먼트를 생성한다.

2. 재조정 단계
이전에 렌더링된 실제 DOM과 새로 렌더링할 React 엘리먼트를 비교하며 변경점을 적용한다.
사용자에게 노출되지 않는 비동기 작업을 진행한다.
파이버 작업(우선순위 지정, 중단, 버림)을 진행한다.

3. 커밋
실제 DOM에 변경 사항을 반영한다.
동기적으로 진행되며, 중단이 불가능하다.

4. 업데이트
props, state 변경시 해당 컴포넌트와 하위 컴포넌트에 대해 1-3 과정을 반복한다.

 

  • 재조정 및 커밋 단계
1. 리액트가 beginWork() 실행해 파이버 작업 수행하며, 자식 없는 파이버 만날 때까지 트리 형식으로 수행한다.
2. completeWork() 실행해 파이버 작업을 완료한다.
3. 형제가 있다면 형제로 넘어가 작업을 진행한다.
4. 모두 끝나면 return으로 돌아가 자신의 작업 종료 알린다.
5. 루트 노드가 완성되면 comitWork() 수행되고, 변경 사항을 비교해 업데이트가 필요한 변경 사항이 DOM에 반영한다.

 

  • 업데이트 단계
    • 최초 렌더링 시에, 모든 파이버를 새로 생성한다.
    • 현재는 이미 파이버가 존재하기에, 기존 파이버에서 업데이트된 props를 받아, 파이버 내부에서 처리한다.
1. setState 업데이트 발생한다.
2. (이미 current 트리 존재함을 확인한다.)
3. setState에 의한 요청 받아 workInProgress 트리 다시 빌드한다.

 

(4) 유의할 점

DOM을 관리하는 브라우저보다 가상 DOM이 무조건적으로 빠른 것은 아니다. 대부분의 상황에서 적용되지만, 동적인 효과가 전혀 없는 정적인 페이지인 경우 가상 DOM을 적용하지 않는 편이 성능적으로 유리할 수 있다.

 

3. 파이버(Fiber)

(0) 파이버 깃허브 주소

react-fiber-architecture: description of React's new core algorithm

 

(1) 파이버 노드

하나의 작업으로 구성된 자바스크립트 객체이다. state가 변경되거나, 생명주기 메서드가 실행되거나, DOM 변경이 필요한 시점에 실행된다. 파이버 재조정자가 관리하며, 이때 재조정은 실제 DOM과 가상 DOM을 비교하는 작업을 말한다.

 

작은 단위로 작업을 나누어 처리하며, 우선순위를 나누어 우선순위가 높으면 빠르게 처리하고 낮으면 연기시키며 유연하게 작업을 처리한다.

 

리액트 요소와의 차이점은 다음과 같다.

  • 파이버: 가급적 재사용된다.
  • 리액트 요소: 계속 새롭게 생성된다.

(2) 파이버 트리

파이버 작업이 끝나면 단순히 포인터를 변경해 workInProgress 트리를 현재 트리로 바꿀 수 있다. 이를 더블 버퍼링이라고 부른다.

해당 로직을 사용해 사용자에게 불완전한 트리를 보여주지 않고, 완전한 버전의 트리만 제공할 수 있다.

 

구성은 다음과 같다.

  • 현재 모습을 담은 파이버 트리
  • 작업 중인 상태를 나타내는 workInProgress 트리

 

해당 트리를 활용하는 과정은 다음과 같다.

1. 기본적으로 current 트리가 존재한다.
2. 업데이트 발생시, 새로 받은 데이터로 workInProgress 트리를 빌드한다.
3. workInProgress 빌드 완료 시, 다음 렌더링에 해당 트리 사용한다.
4. workInProgress 트리가 UI에 반영 완료되면, current 트리가 workInProgress 트리로 변경된다.

 

4. 참고한 도서 및 블로그