Virtual DOM과 Diff 알고리즘에 대해 학습하기 위해서는 먼저, Virtual DOM이 왜 등장했는지에 대해 알아볼 필요가 있다.
DOM(Document Object Model)
브라우저가 HTML 문서를 읽어서 트리 구조의 객체 형태로 바꿔놓은 것이다.
- HTML은 그냥 문자열 문서이고
- DOM은 그 문서를 브라우저가 자바스크립트로 다룰 수 있게 객채화한 결과물이다.
<body>
<h1>Hello</h1>
<p>World</p>
</body>
예를 들어 이런 HTML이 있으면, 브라우저는 아래와 같은 트리로 이해한다.
document
ㄴ html
ㄴ body
ㄴ h1
ㄴ p
이 때 각각의 요소들을 노드라고 부른다.
왜 필요한가?
DOM이 있기 때문에 자바스크립트로 웹페이지를 조작할 수 있다.
예를 들어..
const title = document.querySelector("h1");
title.textContent = "안녕!";
이 코드는 DOM에서 h1 요소를 찾아서 글자를 바꾸는 것이다.
즉, JS는 HTML 원문을 직접 수정하는 게 아니라 DOM 객체를 수정하는 것이다.
핵심 개념
1. 트리 구조
- DOM은 부모-자식 관계를 가진 트리 구조이다.
- body는 h1, p의 부모, h1, p는 body의 자식.
2. 노드
DOM은 여러 종류의 노드로 구성된다.
- Element node : 태그 자체(div, p, h1)
- Text node : 태그 안의 텍스트
- Attribute : 속성 (class, id ..)
3. document 객체
현재 웹페이지의 DOM 전체를 대표하는 객체이다.
브라우저에서 자바스크립트를 실행하면, 현재 열려 있는 HTML 문서를 객체로 다룰 수 있게 해 주는데 그 시작점이 바로 document이다.
console.log(document);
이러면 현재 페이지 전체 문서를 나타내는 객체가 출력된다.
💡HTML과 DOM은 같은 것이 아니다!
HTML : 문서 원본 DOM : 브라우저가 해석해서 만든 메모리상의 객체 구조
→ 즉, HTML은 설계도고 DOM은 그 설계도를 바탕으로 브라우저 안에 만들어진 실제 구조
DOM이 느린 이유(Virtual DOM 등장 배경)
DOM이 느린 이유는 브라우저 화면과 직접 연결된 구조이기 때문이다.
변수값을 바꾸듯이 가볍게 끝나는 것이 아니라, DOM을 바꾸면 브라우저가 화면을 다시 어떻게 보여줄지까지 다시 계산해야 할 수 있다.
1. DOM은 화면과 연결돼 있다.
자바스크립트 객체 하나를 바꾸는 건 메모리 값 변경으로 끝날 수 있지만, DOM 노드는 다르다.
예를 들어..
- 요소 추가
- 글자 내용 변경
- 너비 변경
- 클래스 변경
이런 작업은 단순 데이터 수정이 아니라 브라우저 입장에서는 다음과 같은 사안들을 확인해야 한다.
- 구조가 바뀌었는지
- 위치가 바뀌었는지
- 크기가 바뀌었는지
- 다시 그려야 하는지
2. DOM 변경 뒤 따라오는 브라우저 작업이 무겁다.
Reflow
레이아웃을 다시 계산하는 것이다.
예를 들어 어떤 div 의 with를 바꾸면
- 그 요소 크기가 바뀌고
- 주변 요소 위치도 바뀔 수 있고
- 부모/형제/자식 배치도 다시 계산해야 할 수 있다.
→ 즉 화면 배치를 다시 계산하는 작업이라 비용이 크다.
Repaint
위치는 그대로인데 색상만 바뀌었다고 해도 브라우저는 그 부분을 다시 그려야 한다.
3. JS 객체보다 브라우저 엔진과의 상호작용 비용이 크다.
뒤에 나올 Virtual DOM 이나 일반 JS 객체는 그냥 메모리 안에서 비교하면 된다.
반면 실제 DOM은 브라우저 내부 렌더링 엔진과 연결되어 있어서,
- DOM 트리 갱신
- 스타일 계산
- 레이아웃 계산
- 페인팅
같은 추가 작업이 붙는다.
→ 그래서 “비교”는 JS에서 하고, “진짜 반영”만 최소화하자는 아이디어가 나온 것이다.
💡 DOM이 느린 이유 한 줄 정리
실제 화면과 연결되어 있어서, DOM 변경이 단순 값 수정이 아니라 레이아웃 계산(Reflow)과 다시 그리기(Repaint)까지 유발할 수 있기 때문
Virtual DOM
말 그대로 가상의 DOM이다.
하지만 진짜 브라우저 안에 있는 DOM 노드가 아니라, DOM 구조를 흉내 낸 자바스크립트 객체 트리라고 보면 된다.
- 실제 DOM : 브라우저가 화면을 그리기 위해 관리하는 구조
- Virutal Dom : 그 구조를 js 메모리 안에 가볍게 표현한 복사본
왜 필요한가?
➡️ 실제 DOM은 수정 비용이 크다!
그래서 React 같은 라이브러리에서는 "실제 DOM을 바로바로 많이 만지지 말고, 먼저 메모리 안에서 상태를 계산하고 비교한 다음, 정말 바뀐 부분만 실제 DOM에 반영하자"라는 생각을 하게 된다.
핵심 역할
1. 화면 상태를 메모리 안에 표현
현재 화면이 어떤 구조인지 JS 객체 트리로 들고 있는다.
2. 이전 상태와 현재 상태를 비교
이전 Virtual DOM과 새 Virtual DOM을 비교해서 어디가 달라졌는지 찾는다.
동작 흐름
- 현재 화면 상태를 Virutal DOM으로 표현
- 상태가 바뀌면 새로운 Virtual DOM 생성
- 이전 Virutal DOM과 새 Virtual DOM 비교
- 바뀐 부분만 실제 DOM에 반영
→ 실제 DOM을 바로바로 건드리지 않고, 먼저 두 생태를 비교해서 최소 수정만 한다.
💡Virtual DOM 한 줄 정리
DOM을 그대로 수정하던, Virutal Dom을 사용하던, 결국 마지막에는 실제 DOM을 수정한다.
하지만 Virtual DOM은 실제 DOM을 건드리지 않고, 이전 상태와 비교해서 바뀐 부분만 최소한으로 반영한다는 점에서 그냥 DOM 직접 수정과 다르다.
Diff 알고리즘
이전 Virutal DOM과 새 Virtual DOM을 비교해서 뭐가 바뀌었는지 찾는 규칙이다.

핵심 역할
Diff 알고리즘의 역할은 두 트리를 비교해서 최소 변경 단위를 찾아내는 것 이다.
Virtual DOM은 트리 구조니까, 비교도 보통 루트에서 아래로 내려가면서 한다.
- 부모 노드를 비교하고, 같으면 자식 노드들로 내려가고, 다르면 그 부분은 통째로 바꾸는 식이다.
기본적인 순서
1. 두 노드가 같은 종류인가?
- 둘 다 div인가?
- 둘 다 p 인가?
- 둘 다 텍스트 노드인가?
→ 같은 타입이면 “재사용 가능”하다고 보고 안 쪽을 더 비교한다. 다른 타입이면 보통 그 노드는 통째로 교체한다.
2. 타입이 같으면 내용 비교
둘 다 div 라면:
- 속성이 바뀌었는지
- 자식이 바뀌었는지.. 를 본다.
3. 자식 노드를 재귀적으로 비교
부모가 같으면 그 안의 자식들을 하나씩 비교해 내려간다.
→ Diff는 보통 재귀적 트리 비교이다.
헷갈렸던 부분
1. 수정될 때마다 새로운 Virtual DOM이 생성되는가?
그렇다. 상태가 바뀔때마다 새로운 Virtual DOM이 생성된다.
Virtual DOM은 “수정”하는 것이 아니라 “현재 상태를 표현하는 스냅샷” 이다.
→ 새로운 VDOM을 만들때 조금씩 수정하는 게 아니라 아예 새 트리를 다시 만든다.
💡 VDOM은 보통 불변(Immutable) 구조처럼 다룬다.
-> 기존 VDOM을 수정하는 것이 아니라 항상 새로 생성해야 비교가 수월하다.
2. 이전 VDOM의 이전 VDOM은 ?
React 관점으로 봤을때는 딱 2개만 유지한다.
- Diff가 끝나면 그 이전 것들은 버려진다.
- Diff는 항상 이전 vs 현재 만 비교하면 충분하기 때문이다.