✅ DocumentFragment이란?
DocumentFragment란 Dom 노드를 임시로 구성할 수 있는 가벼운 컨테이너이다. Document와는 달리 DocumentFragment는 메모리상에서만 존재하지 때문에 DocumentFragment로 구성된 트리를 변경하더라도 리플로우가 발생하지 않는다.
이러한 특징을 가진 DocumentFragment를 활용해서 DocumentFragment의 트리에서 DOM 조작을 완료한 후 한번에 실제 DOM에 적용함으로써 리플로우를 최소하하여 성능을 향상시킬 수 있다고 알고있었다.
그래서 이번에 실제로 DocumentFragment를 활용하는 방법과 일반적인 append 메서드를 활용하는 방법의 속도차이를 알아보려고 한다.
💾 예제
DOM을 조작하는 예제는 다음과 같이 간단하게 div를 만들고 text를 추가해준다.
<div id="app"></div>
<script>
const count = 1000;
function createElement(i) {
const element = document.createElement('div');
element.textContent = `${i}번째 div`;
return element;
}
</script>
count 만큼, 반복문을 수행해서 element를 생성하고 DOM을 조작하는데 걸리는 시간을 측정할 예정이다.
1️⃣ appendChild 사용하기
반복횟수만큼 element를 생성하고 즉시 appendChild 메서를 호출하는 방식을 수행한다.
아래와 같이 반복문내에서 element를 추가하고 즉시 #app에 추가하고 있따.
function appendChild() {
const $app = document.getElementById('app');
console.time('appendChild 시간 측정');
for (let i = 0; i < count; i += 1) {
const element = createElement(i);
$app.appendChild(element);
}
requestAnimationFrame(() => {
requestAnimationFrame(() => {
const end = performance.now();
console.log('appendChild 시간 측정 :', end - start, 'ms');
});
});
}
다음 결과를 확인해보니 평균 42.266 ms 정도의 시간이 걸렸다.
appendChild 시간 측정 : 37.89 ms
appendChild 시간 측정 : 41.69 ms
appendChild 시간 측정 : 42.40 ms
appendChild 시간 측정 : 39 ms
appendChild 시간 측정 : 45.60 ms
appendChild 시간 측정 : 47.39 ms
appendChild 시간 측정 : 39.69 ms
appendChild 시간 측정 : 43.5 ms
appendChild 시간 측정 : 42.20 ms
appendChild 시간 측정 : 43.30 ms
2️⃣ append 사용하기
appendChild는 하나의 element 만을 전달받을 수 있지만, append의 경우 한 개 이상의 element를 전달받을 수 있다. 반복문을 실행하는 동안에는 배열에 담았다가 append를 한번 호출했을 때는 어떠한 결과를 보이는지를 측정해본다.
function append() {
const $app = document.getElementById('app');
const start = performance.now();
const list = [];
for (let i = 0; i < count; i += 1) {
const element = createElement(i);
list.push(element);
}
$app.append(...list);
requestAnimationFrame(() => {
requestAnimationFrame(() => {
const end = performance.now();
console.log('append 시간 측정 :', end - start, 'ms');
});
});
}
다음 결과를 확인해보니 평균 40.028 ms 정도의 시간이 걸렸다. appendChild보다는 빠르다고 할 수 있지만 5프로 정도의 차이이기 때문에 이정도면 동일한 것으로 결론을 내려도 될 것 같다.
append 시간 측정 : 36.80 ms
append 시간 측정 : 41.20 ms
append 시간 측정 : 40.39 ms
append 시간 측정 : 39.5 ms
append 시간 측정 : 37.69 ms
append 시간 측정 : 40 ms
append 시간 측정 : 39 ms
append 시간 측정 : 42.10 ms
append 시간 측정 : 44.10 ms
append 시간 측정 : 39.5 ms
3️⃣ DocumentFragment 사용하기
DocumentFragment를 생성하고 반복문을 수행하는 동안에는 DocumentFragment의 트리를 조작 후 결과를 실제 DOM 트리에 반영하는 방식으로 진행한다.
function documentFragment() {
const $app = document.getElementById('app');
const start = performance.now();
const fragment = new DocumentFragment();
for (let i = 0; i < count; i += 1) {
const element = createElement(i);
fragment.appendChild(element);
}
$app.appendChild(fragment);
requestAnimationFrame(() => {
requestAnimationFrame(() => {
const end = performance.now();
console.log('DocumentFragment 시간 측정 :', end - start, 'ms');
});
});
}
다음 결과를 확인해보니 평균 41.166 ms 정도의 시간이 걸렸다. 앞선 두 방법과의 차이가 거의 없다고봐도 무방할 것 같다.
DocumentFragment 시간 측정 : 38.40 ms
DocumentFragment 시간 측정 : 41.60 ms
DocumentFragment 시간 측정 : 44.5 ms
DocumentFragment 시간 측정 : 40.09 ms
DocumentFragment 시간 측정 : 39.90 ms
DocumentFragment 시간 측정 : 39.19 ms
DocumentFragment 시간 측정 : 43.59 ms
DocumentFragment 시간 측정 : 39.39 ms
DocumentFragment 시간 측정 : 41.80 ms
DocumentFragment 시간 측정 : 43.20 ms
🤔 왜 이런 결과가 나오는 걸까?
3가지 방법을 통해서 DOM 트리가 변경되었을 때 걸리는 시간을 비교해보았다. 3가지 중 어떠한 방법을 사용하더라도 걸리는 시간에는 차이가 없는 것으로 보인다.
이를 정확히 확인하기 위해서 Performance 탭을 확인해보았다.
아래 이미지는 appendChild를 수행한 결과이다. 결과를 보면 appendChild 작업이 모두 완료 된 후 Layout 작업이 수행되는 것을 확인할 수 있다.
🎯 결론
최적화가 진행되어 appendChild 즉시 리플로우가 발생하는 것이 아닌 모둔 작업이 완료 된 후에 리플로우 및 리페인트가 되기 때문에 위에 알아본 3가지 방법 중 어떠한 방법을 사용하더라도 비슷한 시간이 걸리게 된다.
'Javascript > 성능' 카테고리의 다른 글
[Javascript - 성능] 리플로우 줄이기 - 3 (requestAnimationFrame - 2) (0) | 2025.07.27 |
---|---|
[Javascript - 성능] 리플로우 줄이기 - 2 (requestAnimationFrame - 1) (0) | 2025.07.26 |
[Javascript - 성능] 리플로우 줄이기 - 1 (0) | 2025.07.20 |
[Javascript - 성능] DOM 렌더링 방식에 따른 성능 비교해보기 - 2 (0) | 2025.06.29 |