DOM / Virtual DOM / 브라우저 렌더링

호돌·2020년 12월 10일
0

프론트엔드

목록 보기
2/11

DOM 이란?

  • 문서 객체 모델은 HTML, XML 문서의 프로그래밍 interface 입니다. DOM은 문서(HTML)의 구조화된 표현을 제공하며 프로그래밍 언어가 DOM 구조에 접근할 수 있는 방법을 제공하여 그들이 문서 구조, 스타일, 내용 등을 변경할 수 있게 돕는 역할을 합니다.

    특징

  • '객체 지향'적 설계

  • HTML 문서 내의 모든 요소를 객체화해서 표현하고 접근토록 함
    문서를 '트리 구조'로 표현
  • HTML 문서를 텍스트가 아닌, 트리 구조를 갖는 객체들의 계층적 구조로 표현
    JavaScript와 같은 script언어를 통해 동적 제어 기능을 제공
  • (삭제,추가,바꾸기,이벤트 처리,수정 등)

그러므로, document를 포함한 html, 그 아래의 트리구조의 태그들 모두 객체이며 모두 객체로서 접근 및 컨트롤 할 수 있습니다.

  • HTML (HyperText Markup Language) : 웹 페이지를 구성하기 위한 마크업 언어

  • XML (eXtensible Markup Language) : 여러 방면으로 사용가능한 마크업 언어

    DOM API 예시로는

  1. document.getElementById(id)

  2. document.createElement(name)

  3. element.style.left

  4. class와 id를 이용한 객체 컨트롤
    등이 있다.

    DOM의 브라우저 렌더링 과정

  • 브라우저가 html을 전달받게 되면 이것을 바탕으로 DOM트리를 구성한다.

  • DOM 트리는 css와 함께 화면을 그려줄 render 트리를 구성한다.

  • layout과 paint를 통해 화면에 보여진다.

    DOM의 단점 및 문제점

  • 브라우저에서 DOM의 변화가 일어나게되면, 브라우저는 위의 렌더링 과정을 다시 거치는 비효율적인 면이 발생함. (한 페이지에서 많은 조작이 일어나는 SPA에서는 더더욱 비효율적임.)

  • DOM의 엘리먼트를 조작하는 과정에서 쓰였던 기존의 document.getElementById()나 제이쿼리 같은 API가 프로그램의 규모가 커지면 엘리먼트의 수도 늘어나고 이벤트도 늘어나기 떄문에 api 조작이 불편해짐

    Virtual DOM

어떤 방식으로 작동되나?

  1. 데이터가 업데이트 되면, 전체 UI를 Virtual DO에 리렌더링 합니다.
  2. 이전 Virtual DOM에 있던 내용과 현재의 내용을 비교합니다.
  3. 바뀐 부분만 실제 DOM에 적용합니다.

특징

  • DOM에 비해 가벼운 복사본
  • in-memory에 존재해서 실제 렌더 되지 않음
  • JavaScript 객체로 이루어진 tree data structure
  • React와 같은 UI라이브러리에 널리 쓰임

Virtual DOM는 어떻게 변경 되는 부분만을 알아 낼 수 있을까?

Reconciliation(재조정)

전체 DOM 트리를 탐색하고 비교하는 일반적인 알고리즘 (diff algorithm)이 있지만, 이 알고리즘은 O(N^3)의 복잡도를 갖습니다.

예를들어, 1000개의 엘리먼트를 그리기 위해 10억 번의 비교연산을 수행해야 합니다. React는 대신, 두 가지 가정을 기반하여 O(n) 복잡도의 휴리스틱 알고리즘을 구현했습니다.

Reconciliation 두 가지 가정

  1. 서로 다른 타임의 두 엘리먼트는 서로 다른 트리를 만들어낸다.(엘리먼트가 다르면 비교하지 않는다)
  2. 개발자가 key prop을 통해, 여러 렌더링 사이에서 어떤 자식 엘리먼트가 변경되지 않아야할지 표시해 줄 수 있다. (key를 통해 비교를 한다.)

부모 노드의 타입이 다르면 자식 노드는 비교하지 않는다.

React는 DOM 트리를 level-by-level로 탐색합니다. 너비 우선 탐색의 일종이라 볼 수 있습니다.

DOM 엘리먼트의 타입이 같은 경우

같은 타입의 두 React DOM 엘리먼트를 비교할 때, React는 두 엘리먼트의 속성을 확인하여, 동일한 내역은 유지하고 변경된 속성들만 갱신합니다.

자식에 대한 재귀적 처리

자식 엘리먼트의 순서가 다른 경우는 매우 비효율적으로 작업을 수행하게 된다.

<ul>
  <li>first</li>
  <li>second</li>
</ul>
⬇︎
<ul>
  <li>zero</li> {/* first가 zero가 됐군. 새로 렌더링! */}
  <li>first</li> {/* second가 first가 됐군. 새로 렌더링! */}
  <li>second</li> {/* 추가됐네. 새로 렌더링! */}
</ul>

이와 같은 비효율적인 문제는 key를 통해 해결 될 수 있다.

<ul>
  <li key="a">first</li>
  <li key="b">second</li>
</ul>
⬇︎
<ul>
  <li key="c">zero</li> {/* 추가됐네. 새로 렌더링! */}
  <li key="a">first</li> {/* 아까 그 녀석이군. 순서만 바꾸자. */}
  <li key="b">second</li> {/* 아까 그 녀석이군. 순서만 바꾸자. */}
</ul>html

Reconciliation Process의 과정

결론

이렇듯 React는 Virtual DOM을 통해 렌더를 한 번으로 줄여 효율적으로 HTML을 제어하고 됩니다.
추가로 리액트를 사용하는것이 무조건적인 성능 향상이 아닙니다. 성능적인 측면도 중요하지만 프론트엔트 뷰 라이브러리를 사용했을 때의 장점은 데이터의 흐름과 구성을 일관되게 해준다는것이 장점입니다. 리액트를 사용하기 전에는 데이터의 소스와 DOM의 조작에 대한 자유도가 높기 때문에 일관된 패턴의 코드를 짜기 어려웠지만 리액트를 사용합으로써 데이터의 흐름을 강제하고, 데이터의 변화에 따라 화면에 변화를 쉽게 확인할 수 있게 되었습니다.

profile
저도 잘 모르는데요?, 내가 몰라서 적는 글

0개의 댓글

관련 채용 정보