DOM(Document Object Model)
DOM(Document Object Model)은 HTML이나 XML 문서의 구조를 표현하는 프로그래밍 인터페이스로, 웹 페이지를 프로그래밍 언어가 이해하고 조작할 수 있는 구조화된 표현이다.
HTML이나 XML 문서를 트리 구조로 표현하여, 각 요소를 노드(node)라는 객체로 다룰 수 있게 해준다.
이는 마치 가계도처럼, 부모-자식 관계로 문서의 구조를 표현한다.
W3C와 WHATWG에 의해 표준화되어 있다.
DOM은 HTML, XML, SVG 문서의 프로그래밍 인터페이스로, 문서의 구조를 메모리에 트리 형태로 표현한다.
주요 목적은 다음과 같다:
- 웹 페이지를 스크립트나 프로그래밍 언어와 연결
- 문서 구조, 스타일, 내용을 동적으로 변경 가능
- 프로그래밍 언어에 문서 접근 및 조작 방법 제공
DOM의 장단점
장점:
- 언어 및 플랫폼 독립적
- 문서 구조를 쉽게 탐색 가능
- 동적이고 사용자 정의 가능
- 파일을 한 번만 파싱
단점:
- 많은 RAM 사용
- 대규모 문서 처리 시 속도 저하
- 복잡한 문서의 경우 메모리 사용량 증가
DOM의 중요성
DOM은 웹 개발에서 핵심적인 역할을 한다:
- 동적 웹 페이지 생성 가능
- 클라이언트 측 변경 구현
- 사용자 상호작용 처리
DOM의 구조와 노드 타입
DOM의 모든 객체는 Node의 한 종류이며, DOM 트리는 여러 종류의 노드로 구성된다:
문서 노드(Document Node): DOM 트리의 최상위에 위치하는 루트 노드이다. 웹 페이지 전체를 대표하며, 다른 모든 노드에 접근하기 위한 진입점 역할을 한다.
요소 노드(Element Node): HTML 요소를 표현하는 노드이다. 웹 페이지의 구조를 형성하는 기본 단위이며, 다른 노드들을 포함할 수 있다.
1 2 3 4 5 6 7 8 9 10
const element = document.querySelector('.myClass'); // Element 노드의 주요 속성과 메서드 element.tagName; // 태그 이름 확인 element.children; // 자식 요소들 접근 element.parentElement; // 부모 요소 접근 element.nextElementSibling; // 다음 형제 요소 element.previousElementSibling; // 이전 형제 요소 element.innerHTML; // HTML 내용 조작 element.classList; // 클래스 목록 관리
텍스트 노드(Text Node): HTML 요소 내의 텍스트 내용을 표현한다.Element 노드의 자식으로 존재하며, 실제 콘텐츠를 저장한다.
속성 노드(Attribute Node): HTML 요소의 속성을 나타낸다. Element 노드의 특성을 정의하는 데 사용된다.
1 2 3 4 5 6 7 8 9
// Attribute 노드 조작 element.getAttribute('class'); // 속성 값 가져오기 element.setAttribute('id', 'newId'); // 속성 설정하기 element.hasAttribute('data-custom'); // 속성 존재 확인 element.removeAttribute('style'); // 속성 제거하기 // 데이터 속성 다루기 element.dataset.customValue = 'hello'; // data-* 속성 설정 console.log(element.dataset.customValue); // data-* 속성 읽기
주석 노드(Comment Node): HTML 주석을 표현한다. 문서 구조에는 영향을 주지 않지만, 개발자들을 위한 정보를 포함할 수 있다.
1 2 3 4 5 6 7 8 9 10 11
// Comment 노드 생성과 사용 const comment = document.createComment('이것은 주석입니다'); element.appendChild(comment); // 주석 노드 찾기 const comments = document.getElementsByTagName('*'); for (let node of comments) { if (node.nodeType === 8) { // 8은 주석 노드를 의미 console.log('Found comment:', node.nodeValue); } }
DocumentFragment Node: 경량화된 Document 객체로, 여러 노드를 그룹화하여 한 번에 DOM에 삽입할 때 사용된다. 성능 최적화에 매우 유용하다.
1 2 3 4 5 6 7 8 9
// DocumentFragment 사용 예시 const fragment = document.createDocumentFragment(); for (let i = 0; i < 1000; i++) { const element = document.createElement('div'); element.textContent = `항목 ${i}`; fragment.appendChild(element); } // 한 번의 DOM 업데이트로 모든 요소 추가 document.body.appendChild(fragment);
DocumentType Node: 문서의 타입을 정의한다. HTML5의 DOCTYPE 선언을 표현한다.
이러한 다양한 노드 타입들은 각각의 특성과 목적을 가지고 있으며, 이들이 서로 연결되어 하나의 완전한 문서 구조를 형성한다. 노드 간의 관계는 부모-자식-형제 관계로 표현되며, 이를 통해 문서의 계층 구조를 표현할 수 있다.
DOM 조작의 기본 작업
요소 선택하기:
요소 생성과 추가:
1 2 3 4 5 6 7 8
// 새로운 요소를 만들고 문서에 추가할 수 있습니다 const newDiv = document.createElement('div'); newDiv.textContent = '새로운 요소입니다'; document.body.appendChild(newDiv); // 요소를 특정 위치에 삽입할 수도 있습니다 const referenceElement = document.getElementById('reference'); document.body.insertBefore(newDiv, referenceElement);
요소 수정하기:
요소 삭제하기:
이벤트 처리
DOM은 사용자 상호작용을 처리하는 이벤트 시스템을 제공한다:
|
|
실제 활용 예시
다음은 DOM을 활용한 실제 웹 애플리케이션의 예시:
|
|
DOM의 성능 고려사항
DOM 조작은 비용이 많이 드는 작업일 수 있다.
따라서 다음과 같은 최적화 기법을 고려해야 한다:
문서 프래그먼트 사용:
캐싱과 최소화:
Virtual DOM
Virtual DOM(가상 DOM)은 웹 애플리케이션의 성능을 최적화하기 위해 사용되는 프로그래밍 개념이다.
실제 DOM의 추상화된 복사본으로, 메모리 상에 존재하는 JavaScript 객체이다.
웹 페이지의 UI를 효율적으로 업데이트하기 위해 사용되며, 주요 목적은 DOM 조작으로 인한 성능 저하를 최소화하는 것이다.
이 HTML은 다음과 같은 DOM 트리를 형성한다:
위의 HTML은 Virtual DOM에서 다음과 같이 표현될 수 있다:
작동 방식
Virtual DOM이 작동하는 과정을 단계별로 살펴보자:
초기 렌더링:
- 처음 페이지가 로드될 때 전체 Virtual DOM이 생성된다.
- 이 Virtual DOM을 기반으로 실제 DOM이 생성된다.
상태 변경 발생:
Virtual DOM 업데이트:
- 새로운 Virtual DOM 트리가 생성된다.
- 이전 Virtual DOM과 새로운 Virtual DOM을 비교한다.
차이점 계산 (Diffing):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// 가상의 Diffing 알고리즘 예시 function diff(oldNode, newNode) { if (!oldNode) { return { type: 'CREATE', newNode }; } if (!newNode) { return { type: 'REMOVE' }; } if (oldNode.type !== newNode.type) { return { type: 'REPLACE', newNode }; } if (oldNode.props !== newNode.props) { return { type: 'UPDATE', props: newNode.props }; } // 자식 노드들에 대해서도 재귀적으로 비교 }
실제 DOM 업데이트:
- 계산된 차이점만을 실제 DOM에 적용한다.
- 이를 ‘재조정(Reconciliation)‘이라고 한다.
Virtual DOM의 이점
성능 최적화:
- 실제 DOM 조작은 비용이 많이 든다.
- Virtual DOM은 메모리 상에서 작업하므로 더 빠르다.
- 여러 변경사항을 한 번에 처리할 수 있다.
크로스 플랫폼:
- Virtual DOM은 실제 DOM에 종속되지 않는다.
- 따라서 웹 외의 플랫폼(예: React Native)에서도 사용 가능하다.
선언적 프로그래밍:
실제 사용 예시
React에서 Virtual DOM을 활용하는 간단한 예시:
|
|
주의사항과 고려사항
항상 더 빠른 것은 아니다:
- 작은 규모의 DOM 조작에서는 오히려 오버헤드가 될 수 있다.
- Virtual DOM의 비교 작업도 비용이 발생한다.
메모리 사용:
- Virtual DOM은 추가적인 메모리를 사용한다.
- 매우 큰 애플리케이션에서는 이를 고려해야 한다.
최적화의 필요성:
Virtual DOM vs. 실제 DOM
비교 기준 | 실제 DOM (Document Object Model) | Virtual DOM |
---|---|---|
정의 | 웹 페이지를 프로그래밍적으로 표현한 실제 문서 객체 모델 | 실제 DOM의 가벼운 복사본으로, 메모리에 존재하는 가상의 DOM 표현 |
데이터 구조 | HTML 요소들의 트리 구조 | JavaScript 객체로 표현된 트리 구조 |
메모리 사용 | 더 많은 메모리 사용 (각 노드가 많은 속성과 메서드를 포함) | 상대적으로 적은 메모리 사용 (필수 속성만 포함) |
업데이트 방식 | 직접적인 DOM 조작으로 즉시 화면에 반영 | 변경사항을 모아서 최적화된 방식으로 한 번에 실제 DOM에 적용 |
업데이트 비용 | 각각의 변경이 리플로우/리페인트를 발생시켜 비용이 큼 | 메모리상에서 먼저 처리되어 실제 DOM 변경을 최소화 |
메모리 사용 | 상대적으로 무거움 | 실제 DOM보다 가벼움 |
조작 속도 | 직접 조작시 느림 (특히 여러 변경사항이 있을 때) | 빠름 (변경사항을 배치로 처리) |
조작 방법 | JavaScript를 통해 직접 조작 가능 | 프레임워크(예: React)를 통해 간접적으로 조작 |
구현 예시 | javascript document.getElementById('app').innerHTML = 'Hello' | javascript const vNode = { type: 'div', props: { id: 'app' }, children: ['Hello'] } |
플랫폼 의존성 | 브라우저 환경에 종속적 | 플랫폼 독립적 (React Native 등에서 활용 가능) |
이벤트 처리 | 각 노드마다 이벤트 리스너 부착 가능 | 루트 노드에만 이벤트 리스너 부착 |
상태 관리 | 상태 변화를 직접 추적하기 어려움 | 상태 변화를 추적하고 관리하기 용이 |
리렌더링 범위 | 변경된 요소와 그 하위 요소 전체를 리렌더링 | 실제 변경이 필요한 부분만 선택적으로 리렌더링 |
디버깅 | 브라우저 개발자 도구로 직접 확인 가능 | 특별한 개발자 도구 필요 (예: React DevTools) |
최적화 방법 | 수동으로 DOM 조작을 최적화해야 함 | diff 알고리즘을 통한 자동 최적화 |
사용 사례 | 간단한 정적 페이지나 최소한의 인터랙션이 필요한 경우 | 동적이고 복잡한 사용자 인터페이스가 필요한 경우 |
장점 | - 직접적인 조작 가능 - 간단한 변경에 적합 - 추가 레이어 없음 | - 효율적인 업데이트 - 성능 최적화 - 선언적 프로그래밍 가능 |
단점 | - 잦은 업데이트시 성능 저하 - 복잡한 상태 관리 어려움 - 크로스 플랫폼 지원 어려움 | - 추가적인 메모리 사용 - 초기 설정 필요 - 간단한 작업에 오버헤드 발생 |
사용 사례
React, Vue.js 등의 현대적인 JavaScript 프레임워크에서 Virtual DOM을 활용하여 UI 렌더링 성능을 최적화한다.