0. 들어가기에 앞서
- 우리는 DOM 트리에 노드를 추가할 때
createElement
와appendChild
를 사용하곤 한다.
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
가 발생하면서 웹페이지에서 노드들이 추가된다.
😖 어?
DocumentFragment
도reflow
가 발생하는데 성능이 왜 좋은걸까?createElement
와DocumentFragment
를 비교하면서 자세히 알아보자
2) createElement와의 차이점와 성능상 이점
(1) createElement와의 차이점
DocumentFragment
가createElement
보다 성능이 좋은 이유는 “reflow
횟수” 때문이다.DocumentFragment
는 미리 노드 조각들을 한 곳에 모아놓고 한 번에 웹페이지에 붙인다.- 그에 반해
createElement
는 하나의 노드 조각만 만들어서 바로 웹페이지에 붙인다.
- 만약 20개에 달하는 노드를 추가한다고 가정했을 때,
DocumentFragment
는reflow
가 약 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
객체를 사용을 고려해봐도 좋을 듯 하다.
반응형
'개발 기술 > 개발 이야기' 카테고리의 다른 글
[Vue] prop drilling을 예방하는 Provider Pattern 알아보기 (2) | 2023.09.30 |
---|---|
팝오버를 라이브러리 없이 웹 API로 구현하는 법, Popover API (0) | 2023.09.17 |
Page Visibility API, 유저가 페이지를 보고 있는지 알려줘! (0) | 2023.07.23 |
내 조직의 리뷰 할당 현황 구하기(3) - github actions로 메시지 스케쥴링하기 (0) | 2023.07.09 |
내 조직의 리뷰 할당 현황 구하기(2) - discord webhook 사용법 (0) | 2023.06.25 |
댓글