개발 기술/개발 이야기

DocumentFragment 객체로, 성능 좋게 DOM 조작하기

by GicoMomg (Lux) 2023. 8. 7.

0. 들어가기에 앞서

  • 우리는 DOM 트리에 노드를 추가할 때 createElementappendChild를 사용하곤 한다.
const p = document.createElement("p"); // 1. 노드를 만들고
document.body.appendChild(p);          // 2. 생성한 요소를 DOM 트리에 추가!

  • 그런데 만약 20개에 달하는 노드를 추가해야할 때는 어떻게 할 수 있을까?
  • appendChild 와 반복문을 사용할 수 있다.
const parent = document.querySelector('#parent');

for (let i = 1; i <= 20; i++) {
    const p = document.createElement('p');
    p.textContent = '!';

    parent.appendChild(p);
}

❓ 하지만 이렇게 직접 DOM에 접근하여 노드를 추가하면 성능에 영향을 주지 않을까?

  • 예상했듯이 성능에 영향을 주는데, 그 이유는 DOM에서 reflow가 발생하기 때문이다.
  • reflow는 요소의 너비, 높이, 위치 등이 변경되어 렌더트리가 재생성되는 걸 말한다.
  • reflow는 비용이 큰 작업인데, 그 이유는 특정 요소에서 리플로우가 발생하면 주변 요소(부모, 자식, 형제)에도 영향을 주기 때문이다. (reflow에 대해 더 알아보고 싶다면 이 포스팅 참고)
  • 앞선 예시처럼 여러 개의 노드를 추가하면, 부모의 높이가 변해 reflow가 발생하여 성능에 영향을 준다.

🧐 그럼 어떻게 해야 성능에 영향을 덜 주면서 요소들을 추가할 수 있을까?
이번 시간에는 성능 좋게 DOM을 조작할 수 있는, DocumentFragment에 대해 알아보았다!



1. DocumentFragment와 성능 개선

1) DocumentFragment는 무엇일까?

(1) 개념

  • DocumentFragment은 여러 DOM 요소들을 메모리에 일시적으로 저장할 수 있는 객체이다.
  • DocumentFragment는 일반 HTML DOM처럼 요소를 추가하거나 조작할 수 있는데, 이 과정 동안 웹 페이지에는 아무런 시각적 변화가 없다.
  • 대신 여러 개의 요소들을 모아두었다가 준비가 되면, DocumentFragment의 요소를 한 번에 HTML DOM에 추가된다.

(2) 사용법

  • 아래 코드는 DocumentFragment를 사용해 여러 DOM 요소들을 메모리에 저장했다가
  • 한 번에 웹페이지에 추가하는 예제이다. 코드를 한 번 살펴보자
<ul id="list"></ul>
const ul = document.getElementById('list');
const fragment = document.createDocumentFragment();  // (a)

for (let i = 0; i < 10; i++) {         
    const li = document.createElement('li');        // (b)
    li.textContent = `아이템 ${i + 1}`;
    fragment.appendChild(li);
}

ul.appendChild(fragment); // (c) 
  • (a) 우선 createDocumentFragment를 사용해 메모리 저장 공간을 만든다.
  • (b) 그 다음 반복문을 사용해 여러 개의 노드를 DocumentFragment에 저장한다. 이 과정 동안 웹페이지에 시각적 변화는 없다.
  • (c) DocumentFragment에 모아둔 요소들을 한 번에 웹페이지에 추가한다. 이때 reflow가 발생하면서 웹페이지에서 노드들이 추가된다.

😖 어? DocumentFragmentreflow가 발생하는데 성능이 왜 좋은걸까?
createElementDocumentFragment를 비교하면서 자세히 알아보자



2) createElement와의 차이점와 성능상 이점

(1) createElement와의 차이점

  • DocumentFragmentcreateElement보다 성능이 좋은 이유는 “reflow 횟수” 때문이다.
  • DocumentFragment는 미리 노드 조각들을 한 곳에 모아놓고 한 번에 웹페이지에 붙인다.
  • 그에 반해 createElement는 하나의 노드 조각만 만들어서 바로 웹페이지에 붙인다.

  • 만약 20개에 달하는 노드를 추가한다고 가정했을 때, DocumentFragmentreflow가 약 1~3번 내외로 발생한다면,


  • createElement 는 매번 노드를 생성하고 웹 페이지에 노드를 추가하기에 20번 이상의 reflow가 발생하게 된다.



  • 그렇기 때문에, 여러 요소들을 하나씩 웹페이지에 추가하는 createElement보다 여러 요소를 한 번에 추가하는 DocumentFragment가 더 빠르고 성능이 좋은 것이다.
 DocumentFragment  createElement
용도  - 임시로 요소들을 메모리에 모아두기 위해 사용됨  - 하나의 요소를 만들기 위해 사용됨
역할  - 여러 요소들을 담는 컨테이너 역할  - 하나의 새로운 HTML 요소를 생성
DOM 적용 방식  - DocumentFragment에 추가된 요소들은
 바로 웹페이지에 보이지 않음
 - createElement로 만든 요소는 DOM에 바로 추가
노드 추가 방식  - 여러 요소들을 모아두었다가
 한번에 웹페이지에 추가
 - 한 번에 하나의 요소만을 만들어 웹페이지에 추가
활용 방향  - 여러 개의 DOM 변경을 한 번에 처리하고 싶을 때
 - 복잡한 DOM 조작을 최적화하고 싶을 때
 - 한 번에 하나의 요소만 추가하고 싶을 때
 - 기본적인 DOM 조작과 단순히 요소를 생성하고 싶을 때
성능  - 여러 요소를 모아두었다가 한번에 적용하므로,
 리플로우(Reflow)와 리페인트(Repaint)가 적게 발생하여 성능에 좋음
 - 여러 요소를 하나씩 추가하므로, 리플로우와 리페인트가 더 많이 발생

(2) 성능 비교

  • 아래 예시는 노드가 DOM에 추가되는 시간을 비교한 예제이다.

See the Pen DocumentFragment by KumJungMin (@kumjungmin) on CodePen.

See the Pen createElement by KumJungMin (@kumjungmin) on CodePen.



  • 결과적으로 노드가 추가될 때, DocumentFrgment는 0.5ms, createElement는 4.5ms가 소요됐다.
  • 이처럼 단순히 노드 추가 시간만 비교했을 때 DocumentFrgment가 더 빠른 걸 알 수 있었다.



2. 마치며…

  • 페이지에 여러 노드를 추가할 때는 주변 요소의 위치나 높이 등이 변경되어 리플로우(reflow)가 발생하면, 성능에 영향을 주게 된다.
  • 이번 시간에는 DOM 조작시 reflow를 줄일 수 있는 방법으로, DocumentFragment 객체를 알아보았다.
  • DocumentFragment는 여러 DOM 요소를 일시적으로 저장하는 객체로, 한 번에 요소를 페이지에 추가할 수 있어 reflow 발생횟수를 줄일 수 있었다.
  • 만약 여러 개의 노드를 조작해야한다면, reflow 횟수를 줄일 수 있는 DocumentFragment객체를 사용을 고려해봐도 좋을 듯 하다.

반응형

댓글