DocumentFragment는 DOM 트리에는 존재하지 않고 메모리상에서만 존재하는 DOM 노드다.
DocumentFragment는 DOM에 반영되기 전까지는 DOM 트리가 아닌 메모리상에서만 존재하기 때문에 구조에 변경이 일어나도 브라우저가 다시 화면을 렌더링하지 않는다. 즉, 불필요한 reflow나 repaint가 발생하지 않아 성능 최적화를 위해 사용된다.
DocumentFragment를 사용하면 왜 성능 최적화에 유리한지 예시를 통해 확인해보자
const userList = [{ name: "철수" }, { name: "민희" }];
const ul = document.querySelector("ul");
// DocumentFragment 생성
const fragment = document.createDocumentFragment()
// const fragment = new DocumentFragment();
for (const { name } of userList) {
const li = document.createElement("li");
li.textContent = name;
fragment.appendChild(li);
}
ul.appendChild(fragment);
위와 같이 두개의 li
를 fragment에 담아 appendChild
한번의 렌더링으로 두개의 리스트를 그릴 수 있다.
그리고 확인해보면, fragment 없이 <li>
태그가 <ul>
안에 삽입됐다.
위의 첫 번째 예제에서 <li>
를 fragment
가 아닌 <ul>
에 직접 appendChild
를 했다면 유저의 숫자만큼 repaint와 reflow 작업이 실행될 것이다. 하지만 fragment를 사용했기 때문에 한 번의 렌더링으로 모든 화면을 그릴 수 있습니다.
만약 위에 코드를 바꾸어 <ul>
을 createElement
로 만들고 <ul>
에 <li>
를 삽입해 위와 동일하게 한번의 렌더링만 한다면 굳이 documentFragment
를 쓸필요 없는거 아닐까?
const userList = [{ name: "철수" }, { name: "민희" }];
const ul = document.createElement("ul");
for (const { name } of userList) {
const li = document.createElement("li");
li.textContent = name;
ul.appendChild(li);
}
document.body.appendChild(ul);
실제로 이 경우 documentFragment를 사용하지 않고 createElement를 활용해도 무방하다
documentFragment가 유용한 경우는 형제 위치에 있는 여러개의 노드를 한번의 렌더링으로 그려줄 수 있기 때이다.
createElement
를 했을 때와 createDocumentFragment
를 했을 때의 퍼포먼스 측정도 뚜렷한 우세가 없었기 때문에 이 경우 상황에 맞게 두 방법중 하나를 택하면 된다.
여기서는 documentFragment
를 사용하길 권한다.
documentFragment와 appendChild를 성능 비교한 실험을 보면 많은 노드가 추가될 수록 createDocumentFragment
로 작업때 더 좋은 퍼포먼스를 보이고 있다.
그리고 두번째로는 append와appendChild를 성능 비교한 실험을 봤을때 append
에 여러 element를 동시에 넘기는것 보다 appendChild
를 element수 만큼 실행하는게 더 빠른 퍼포먼스를 보이는걸 확인 할 수 있었다.
그렇기 때문에 퍼포먼스가 중요한 경우에는 documentFragment
를 쓰는것이 유리하다고 판단한다.
documentFragment를 Dom에 추가하면 documentFragment에 쌓여있던 자식노드들은 더이상 존재하지 않게 된다.
const userList = [{ name: "john" }, { name: "jason" }, { name: "milli" }];
const ul = document.querySelector("ul");
const fragment = document.createDocumentFragment();
for (const { name } of userList) {
const li = document.createElement("li");
li.textContent = name;
fragment.appendChild(li);
}
console.log(fragment.hasChildNodes()); // true
ul.appendChild(fragment);
console.log(fragment.hasChildNodes()); // false
참고
https://velog.io/@oneook/DocumentFragment-객체는-무엇이며-왜-써야할까
https://7942yongdae.tistory.com/70
https://blog.hao.dev/web-api-appendchild-v-s-createdocumentfragment