관련 포스팅은 따로 공부했으니 간단하게 과정만 짚고 넘어가보자.
브라우저는 HTML, CSS 리소스 등을 파싱하여 DOM트리, CSSOM트리를 생성하고 둘을 합쳐서 Render트리를 만든다. 그 후에 레이아웃(reflow)와 페인팅을 거쳐서 사용자에게 보여지게된다.
여기서 비용이 생기는 부분은 다시 레이아웃과정을 거치고 페인팅과정을 거치는 것이다. 이에 대한 비용을 줄이기위해 가상돔이라는 개념이 만들어졌다.
예를 들어 고쳐야할 노드가 30개가 있는데 이것을 일일히 하나씩 다 조작한다면 30번의 레이아웃, 페인팅 작업이 생길 것이다. 딱봐도 전체적인 프로세스에 비효율적이다.
가상돔을 더블버퍼링이라고 생각하자. 돔에 변화가 생기면 그것을 가상돔에 적용시키는 것이다. 이 가상돔 트리는 최종적인 변화를 실제 돔에게 딱 한번 던져주게된다. 모든 변화를 하나로 묶어서 한번 던져주는 것이다.
이 개념을 생각해보니 이전에 DOM fragment를 통해 생성되어야할 노드들을 모두 만들고 fragment에 추가해서 실제 돔에 딱 한번 적용했던 예제가 생각이 났다. 가상돔이란 이와 비슷한 원리인 것이다. 이 과정을 조금 더 추상화, 자동화 시켰다고 생각하면 된다.
가상돔이 돔관리를 함으로써 컴포넌트끼리 돔 조작 정보에 대해 공유할 필요도 없고 기존값에서 어떤값으로 변경되었는지에 대한 정보를 매번 기억할 필요가 없다.
export default class View {
constructor() {
const target = document.querySelector('main');
this.$newEl = target.cloneNode(true); // virtual DOM의 역할을 한다.
this.$newEl.innerHTML = this.getTemplate();
target.replaceWith(this.$newEl);
}
getTemplate() {
return `<ul></ul>`;
}
displayTodo(todoList) {
const ul = this.$newEl.querySelector('ul');
ul.innerHTML = `${todoList.map((todo) => `<li data-id=${todo.id}">${todo.text} ${todo.id}</li>`).join('')}`;
}
}
위의 설명을 보면 $newEl
이 왜 가상돔의 역할을 하는지 알게된다.
target노드를 복사해서 $newEl
을 만들고 innerHTML을 통해 todoList내용을 추가한 다음에 target노드를 $newEl
로 교체한다.
결국에 target에 곧바로 변경된 DOM을 적용하는 것이 아니라 $newEl
을 한번 거쳐서 변경된 내용을 딱 한번 노드 교체를 통해 적용시키는 것이므로 가상돔의 역할이라고 볼 수 있다.