JavaScript/DOM

[JavaScript]DocumentFragment 객체 사용 방법

DevStory 2022. 12. 2.

DocumentFragment 객체 사용 방법

DOM은 브라우저가 웹 페이지에 콘텐츠(내용 또는 데이터) 표현 방법을 결정하는 데 사용되는 HTML 문서의 논리적 표현으로 문서 객체 모델(Document Object Model)의 약어입니다. DOM은 JavaScript에서 DOM을 조작(요소 추가, 요소의 순서 변경)할 수 있도록 유용한 API도 제공합니다.

 

하지만, DOM을 과도하게 조작하거나 접근하면 콘텐츠를 웹 페이지에 표현하는 속도가 느려지므로 주의해야 합니다.

 

이번 포스팅은 DOM 조작의 문제점과 이를 해결할 수 있는 DocumentFragment에 대해 설명합니다.


DOM Reflow와 Repaint

먼저 ReflowRepaint라는 두 가지 용어에 대해 알아봅시다. Reflow는 새로운 HTML 요소를 추가하거나 순서를 이동시키기 위해 HTML 요소들의 위치과 크기를 다시 계산한다는 의미입니다. Repaint는 레이아웃을 다시 그린다는 의미입니다.

 

일반적으로 Reflow가 발생하면 Repaint가 발생합니다. 만약 DOM 조작이 발생한 HTML 요소가 레이아웃에 영향을 주지 않는 경우에는 Repaint만 발생합니다. 예를 들어, 특정 HTML 요소의 배경색 스타일을 변경하는 경우 위치 및 크기는 변경되지 않으므로 Repaint만 발생합니다.

 

Reflow는 대량의 DOM을 조작하는 경우 웹 페이지의 성능을 저하시킵니다. 웹 페이지 성능에 영향을 줄 수 있는 다음 예제를 살펴봅시다.


DOM 조작 예제

아래는 HTML 마크업이며, DOM을 조작하여 <ul> 요소에 <li> 요소를 추가합니다.

<div id="content">
  <ul id="ul-list">
  </ul>
</div>

 

아래는 배열의 요소를 <li> 요소로 추가하는 JavaScript 소스 코드입니다.

const items = ['item-1','item-2','item-3','item-4'];
const ulNode = document.getElementById("ul-list");

items.forEach(function(item) {
  // 순서 1. li 요소 생성
  const liNode = document.createElement('li');
  
  // 순서 2. li 요소의 텍스트를 배열의 요소로 설정
  liNode.innerText = item;
  
  // 순서 3. li 요소를 DOM에 적용
  ulNode.appendChild(liNode);
});

배열의 요소를 forEach() 메서드로 순회하여 DOM에 추가하였습니다. 다음은 forEach() 메서드가 실행되면서 일어나는 과정입니다.

 

[동작 과정]

순서 1. <li> 요소를 생성합니다.(DOM에 영향 없음)

순서 2. <li> 요소의 텍스트를 배열의 요소로 설정합니다.(DOM에 영향 없음)

순서 3. <li> 요소를 id가 "ul-list"인 <ul> 요소에 추가합니다.(DOM에 영향 발생)

순서 4. <li> 요소를 <ul> 요소에 추가하면서 Reflow가 발생합니다.(DOM에 영향 발생)

 

DOM에 추가하려는 HTML 요소가 많거나 DOM을 접근하는 빈번하게 접근하는 경우 Reflow가 많이 발생합니다.


DocumentFragment 사용

DocumentFragment 객체는 DOM 요소를 저장하는 임시 저장소입니다. DocumentFragment 객체는 DOM 트리의 일부가 아니므로 수정 및 변경이 발생해도 웹 페이지에 영향을 미치지 않습니다.

 

아래는 배열의 요소를 DocumentFragment 객체를 활용하여 <li> 요소로 추가하는 JavaScript 소스 코드입니다.

const items = ["item-1", "item-2", "item-3", "item-4"];
const ulNode = document.getElementById("ul-list");
const fragment = new DocumentFragment();

items.forEach(function (item) {
  // 순서 1. li 요소 생성
  const liNode = document.createElement("li");

  // 순서 2. li 요소의 텍스트를 배열의 요소로 설정
  liNode.innerText = item;

  // 순서 3. li 요소를 DocumentFragment에 추가
  fragment.appendChild(liNode);
});

// 순서 4. forEach() 메서드가 끝난 후 DOM에 DocumentFragment 객체를 추가
ulNode.appendChild(fragment);

임시 저장소인 DocumentFragment 객체를 조작 후 DOM 트리에 DocumentFragment 객체를 추가하면 되기 때문에 한 번의 Reflow만 발생합니다.


정리

  • Reflow는 새로운 HTML 요소를 추가하거나 순서를 이동시키기 위해 HTML 요소들의 위치과 크기를 다시 계산한다는 의미입니다. 일반적으로 Reflow가 발생하면 Repaint가 발생합니다.
  • Repaint는 DOM 레이아웃을 다시 그린다는 의미입니다.
  • DocumnetFragment 객체는 임시 저장소 역할을 수행합니다.
반응형

댓글