[1008] React복습: Critical Rendering Path, 가상 DOM

방법이있지·2025년 10월 8일

웹개발

목록 보기
14/19
post-thumbnail

React를 공부하신 분들이라면 가상(Virtual) DOM이라는 말을 한번쯤은 들으셨을 법도 한데, 이게 왜 중요한지는 가물가물하실 겁니다.

그래서 글로 정리해보았어요들레이요.

Critical rendering path

웹사이트를 화면에 표시할 때 HTML, CSS, JavaScript가 사용된다는 건 아실 거에요.

실제로는 HTML, CSS, JavaScript 코드가 화면에 보이는 웹사이트로 변신(?)될때까지는 일련의 과정이 이루어지는데, 이를 Critical Rendering Path라 합니다.

대충 과정을 정리해 보자면

HTML 코드                           DOM 트리
--------------------------------    ----------------------------
<html>                              [html]
  <body>                                ├── [body]
    <h1>무적 LG</h1>                     │     ├── [h1] "무적 LG"
    <p>끝까지 TWINS</p>                        │     └── [p] "끝까지 TWINS"
  </body>                               └──
</html>
--------------------------------    ----------------------------
CSS 코드                             CSSOM 트리
--------------------------------    ----------------------------
h1 { color: pink; }                  [CSSOM]
p  { font-size: 24px; }                 ├── [h1]
                                        │     └── color: pink
                                        └── [p]
                                              └── font-size: 24px
--------------------------------    ----------------------------

1단계 HTML 코드는 DOM(Document Object Model), CSS 코드는 CSSOM (CSS Object Model)로 전환됩니다.

  • DOM 및 CSS Object Model은, 각각 HTML / CSS 코드를 브라우저가 이해하기 쉬운 형태로 변환한 트리 구조의 객체를 뜻합니다.
  • 이때 JavaScript는 DOM을 수정하는 역할을 합니다. 예를 들어 버튼을 누르면 표시되는 숫자가 1씩 늘어나는 기능을 구현하면, DOM 중 해당 숫자에 해당되는 부분이 수정되겠죠.

2단계 DOM + CSS Object Model을 합쳐서 렌더 트리를 만듭니다.

  • 특별한 건 아니고 두 모델이 합쳐진 거라고 생각하면 됩니다.
  • 화면에 렌더링되는 요소들의 모든 정보가 포함되어 있는, 웹사이트의 설계도이자 청사진 역할을 합니다.

3단계 렌더 트리 내 요소의 위치를 계산하는 Layout 단계가 진행됩니다.

  • DOM이 변경돼서 Layout이 다시 진행되는 과정을 Reflow라고도 합니다

4단계 레이아웃이 계산된 요소들을 실제로 웹사이트에 그리는 Paint 단계가 진행됩니다.

  • DOM이 변경돼서 Paint가 다시 진행되는 과정을 Repaint라고도 합니다

DOM이 수정될 때

앞서 언급했듯이 JavaScript로는 DOM을 수정할 수 있습니다.

이런 경우 브라우저는 다시 render tree를 생성하고(2단계), 웹사이트의 레이아웃을 다시 잡는 reflow를 거치고(3단계), 렌더링 역시 다시 하여 repaint(4단계)도 거치게 됩니다.

문제는 reflowrepaint에는 큰 시간적 비용이 든다는 점입니다. 그래서 DOM 수정이 많아질수록 웹사이트 성능이 급격히 떨어집니다.

이를테면, <ul>에 0부터 2999까지 <li>를 삽입하는 함수를 만들었다고 합시다

function badPractice() {
  const $ul = document.getElementById("ul");
  for (let i = 0; i < 3000; i++) {
    $ul.innerHTML += `<li>${i}</li>`;
  }
}

위 함수에서는 무려 3000번 DOM 수정을 하게 됩니다. reflowrepaint 역시 오래 걸리기 때문에, 실제로 <li> 태그 내용이 다 생성되려면 상당한 시간이 소요됩니다. 즉 렌더링이 많이 느려지므로, 이렇게 코드를 짜시면 안 됩니다.

function goodPractice(){
  let list = "";
  for (let i = 0; i < 3000; i++){
    list += `<li>${i}</li>`
  }
  const $ul = document.getElementById("ul");
  $ul.innerHTML = list;
}

대신 이렇게 list라는 String 매개변수를 선언한 뒤, <li> 태그에 해당하는 내용을 미리 저장해 두고, DOM은 단 1번 수정하는 식으로 코드를 짜시면 됩니다.

이렇게 한꺼번에 변경사항이 많을 경우, 매번 따로 DOM 수정을 하기보단, 한 번에 모아서 수정을 해야 합니다.

Virtual DOM

React에서는 컴포넌트와 state를 통해 업데이트를 관리한다는 점을 기억합시다. 컴포넌트 내 State가 바뀔 때마다 컴포넌트 UI가 업데이트되는 방식이였죠.

앞선 논리대로라면 여러 업데이트가 발생할 시, 모아서 한 방에 DOM에 반영해야 하는 게 좋을 겁니다. 이를 위해 리액트는 Virtual DOM을 사용하는데요, 이는 실제 브라우저가 렌더링하는 DOM을 자바스크립트 객체로 흉내낸 거라고 생각하면 됩니다.

자세한 동작과정을 보자면

  • 각 컴포넌트는 자신만의 Virtual DOM 트리를 가지고 있습니다.
  • 컴포넌트 state가 바뀌면, 해당 컴포넌트의 Virtual DOM이 갱신됩니다.
  • 이전 Virtual DOM과 새로운 Virtual DOM을 비교합니다(diffing)
  • 여러 컴포넌트가 동시에 바뀌면, React는 모든 Virtual DOM에서 변경 사항을 모아 한 번에 실제 DOM에 반영합니다(batch)

이러면 Reflow, Repaint가 최소화되어 훨씬 빠른 렌더링이 가능해집니다. 우와~

profile
뭔가 만드는 걸 좋아하는 개발자 지망생입니다. 프로야구단 LG 트윈스를 응원하고 있습니다.

2개의 댓글

comment-user-thumbnail
2025년 10월 9일

우와 짱이당~

1개의 답글