Virtual DOM 가상돔
React의 대표적인 특징 중의 하나는 virtual DOM이 있다는 것입니다.
가상 DOM을 이해하기에 앞서 DOM과 browser의 rendering과정부터 알아야 합니다.
DOM (Document Object Model) : HTML 문서 구조를 계층구조의 객체로 표현
HTML로 구성된 웹 페이지와 프로그래밍 언어(ex. JavaScript)를 연결시켜 주는 역할
브라우저의 렌더링과정은 아래와 같습니다.
- 브라우저가 사용자가 요청한 주소를 방문해 HTML파일을 다운로드한다.
- 서버로부터 html 문서를 전달받으면, 브라우저 엔진은 위에서 아래로 순차적으로 파싱 하며 태그와 속성들을 DOM tree형태로 메모리에 저장한다.
- 2번 과정에서 css 링크나 스타일 태그를 만나면 CSSOM tree로 변환한다.
- 문서의 파싱이 완료되면 두 트리를 결합하여 Render tree를 생성한다.
- Render tree는 브라우저 상에서 위치와 크기를 결정하는 Reflow과정을 거치며,
색상 등 시각적 요소를 render tree에 업데이트하는 Repaint 과정을 진행하여 렌더링을 완료한다.
가상돔을 왜 만들었을까?
위의 과정에서 보다시피 브라우저의 렌더링과정은 매우 복잡하고 많은 비용이 듭니다.
요즘 대다수의 앱은 렌더링이 된 이후 정보를 보여주는 단순 동작뿐만 아니라,
사용자의 인터랙션을 통해 추가적으로 다양한 정보를 노출합니다.
따라서 렌더링이 완료된 이후에도 사용자의 인터랙션으로 웹이 변경되는 상황 또한 고려해야 합니다.
Single Page Application에서는 렌더링 이후의 추가 렌더링작업이 하나의 페이지에서 모두 일어나므로 계속해서 Reflow, Repaint작업이 생겨납니다.
하나의 Reflow가 발생하면 Repaint는 필연적으로 일어나며, 부모 요소에서 변경사항이 발생하면 하위 자식 요소도 덩달아 변경되어야 하기 때문에 많은 비용이 발생하게 됩니다.
이러한 문제점을 개선하기 위하여 탄생한 것이 virtual DOM입니다.
가상돔은 말 그대로 실제 브라우저의 DOM이 아닌 React가 관리하는 가상의 돔입니다.
가상돔은 웹페이지가 표시해야 할 DOM을 우선 메모리에 저장하고, react가 실제 변경에 대한 준비가 완료되었을 때 실제 DOM에 반영합니다.
이렇게 DOM 계산을 브라우저가 아닌 메모리에서 계산하는 과정을 거치게 된다면 실제로는 여러 번 발생했을 렌더링 과정을 최소화할 수 있으므로 브라우저와 개발자의 부담을 덜 수 있습니다.
그렇다면 React는 어떻게 여러 번의 렌더링 과정을 압축하여 최소한의 렌더링 단위를 만들어 낼까요?
이러한 가상 DOM과 렌더링 과정 최적화를 가능하게 해주는 것이 React Fiber 리액트 파이버입니다.
React Fiber
React Fiber라는 용어는 낯설게 다가오지만, 간단히 말하자면 리액트에서 관리하는 평범한 자바스크립트 객체입니다.
이 Fiber객체는 React component에 대한 정보를 1:1로 가지고 있습니다.
파이버는 파이버 재조정자(Fiber reconciler)가 관리하는데, 이는 가상 DOM과 실제 DOM을 비교하여 변경사항을 수집하여
변경 사항을 가지고 있는 파이버를 기준으로 화면에 렌더링을 요청하는 역할을 합니다.
초기의 조정 알고리즘은 stack 알고리즘으로 이루어져 동기적으로 작동되어, 하나의 작업이 시작되면 중단될 수 없다는 비효율성을 가졌습니다. 이러한 비효율성을 해결하기 위해 스택 조정자대신 파이버라는 개념을 탄생시켰습니다.
파이버의 작업순서는 아래와 같습니다.
- (비동기) 렌더 단계에서 react는 사용자에게 노출되지 않는 모든 비동기 작업을 수행한다.
파이버는 하나의 작업 단위로 구성되어 있고 react는 이런 작업단위 하나씩 처리하고 finishedWork()로 마무리한다. - (동기) DOM에 실제 변경 사항을 반영하는 commitWork() 작업을 동기식으로 처리한다.
파이버 객체는 아래의 코드처럼 단순한 자바스크립트 객체로 구성되어 있습니다.
이 객체 값에서도 알 수 있듯이 React의 핵심 원칙은 UI를 문자열, 숫자, 배열과 같은 값으로 관리한다는 것입니다.
변수에 이러한 UI값을 보관하고, React의 JavasSript 코드의 흐름에 따라 이를 관리하고, 표현하는 것이 바로 React라고 할 수 있습니다.
function FiberNode(tag, pendingProps, key, mode) {
// Instance
this.tag = tag
this.key = key
this.elementType = null
this.type = null
this.stateNode = null
// Fiber
this.return = null
this.child = null
this.sibling = null
this.index = 0;
...
}
Fiber Tree
파이버의 개념에 대해서 알아보았으니, 그다음으로는 파이버 트리에 대해 알아보겠습니다.
파이버 트리는 React 내부에서 2개가 존재합니다.
하나는 현재의 모습, 다른 하나는 작업 중인 상태를 나타내는 workInProgress tree입니다.
파이버의 작업이 끝나면 리엑트는 포인터만 변경하여 workInProgress tree를 현재 트리로 바꿔버립니다.
이를 더블 버퍼링 Double Buffering이라고 하고, 이 더블 버퍼링은 커밋 단계에서 수행됩니다.
이러한 기법으로 인해 user에게 미완성인 상태를 노출하지 않고 자연스럽게 완성된 다음 상태를 보여 줄 수 있습니다.
Double Buffering
: 보이지 않는 곳에서 다음으로 그려야 할 그림을 미리 그린다음, 이것이 완성되면 현재 상태를 새로운 그림으로 바꾸는 기법
최초 렌더링 시에는 모든 파이버를 새로 만들지만, 이후에 일어나는 변화에는 새로운 파이버 객체를 만드는 리소스 낭비를 줄이기 위해
내부 속성값만 초기화하거나 바꾸는 형태로 파이버트리를 업데이트합니다.
과거에는 재귀적으로 하나의 트리를 순회해 새로운 트리를 만드는 작업을 동기식으로 진행하고 한번 진행되면 중단될 수 없었습니다.
현재에는 우선순위가 높은 다른 업데이트가 오면 현재 업데이트 작업을 일시 중단하거나 새롭게 만들 수 있습니다.
또한, 작업단위를 나누어 우선순위를 할당하는 것도 가능합니다. React는 이러한 작업을 Fiber 단위로 나눠서 수행합니다.
Fiber와 가상 DOM 정리
실제 브라우저 구조인 DOM에 브라우저의 변경사항을 반영하는 작업은 동기적으로 일어나고 이러한 작업이 많이 일어나게 되면 화면에 불완전하게 표시될 수 있는 가능성이 높아지므로 이러한 작업을 가상에서
즉, 메모리상의 가상 DOM에서 Fiber가 비동기적으로 작업하여 최종적인 결과물만 파이버 재조정자(Fiber reconciler)가 실제 브라우저 DOM에 적용을 합니다.
가상 DOM과 React의 핵심은 브라우저의 DOM을 더 빠르게 그리고 반영하는 것이 아니라, 값으로 UI를 표현한다는 것에 있습니다.
화면에 표시되는 UI를 자바스크립트의 문자열, 배열 등과 같이 관리하고 이러한 흐름을 효율적으로 관리하기 위한 메커니즘이 핵심이라고 할 수 있습니다.
'Study > React' 카테고리의 다른 글
React 깊이 이해하기(4) - useState (1) | 2024.11.09 |
---|---|
React 깊이 이해하기(3) - React Rendering (1) | 2024.11.08 |
React 깊이 이해하기(2) - Life cycle (0) | 2024.11.07 |