About VirtualDOM

yongkini ·2021년 12월 5일
2

React

목록 보기
19/19
post-custom-banner

Chapter

1) VirtualDOM에 대한 설명 및 VirtualDOM이 나오기 전과의 비교
2) VirtualDOM vs IncrementalDOM
3) VirtualDOM의 한계 및 유의점

VirtualDOM에 대한 설명 및 VirtualDOM이 나오기 전과의 비교

1) DOM이란?
: DOM이란 Document Object Model의 약자로, 브라우저가 html 파일을 다루기 쉽고, 이해할 수 있도록 파싱하는 과정에서 토큰나이징, 트리 구조로 노드화한 결과물로 HTML의 계층적 구조를 객체화한 '트리 구조의 객체'라고 할 수 있다.

2) DOM은 어디에 쓰이는가?

  • CSSOM과 함께 렌더트리를 구성하는 데에 쓰이고, 최종적으로 이 렌더 트리를 바탕으로 렌더링을 하게되기 때문에 브라우저 렌더링의 핵심 역할 중에 하나다.
  • 브라우저가 제공하는 WebAPIs 중에 하나인domAPI를 통해서 html 구조, ui 등을 조작할 때 쓰인다. 이에 따라 리렌더링을 할 때도 DOM을 거칠 수 밖에 없다.

3) VirtualDOM은 무엇인가?
: VirtualDOM은 말그대로 가상의 DOM으로 메모리상에 생성해놓은 DOM을 모방한 자바스크립트 객체이고, 이러한 VirtualDOM을 사용하는 대표적인 라이브러리로 React가 있다.

4) DOM이 있는데 굳이 가상 DOM(VirtualDOM)을 만든 이유는 뭔가?
: 사실 현대의 DOM은 자체적으로도 굉장히 빠르고, 효율화됐기 때문에 DOM 자체가 느리거나, 퍼포먼스가 안좋아서 VirtualDOM이 필요하다는 말은 잘못됐다고 생각한다. 그러면 도대체 메모리 상에 그렇게 작지도 않은 VirtualDOM을 그것도 2개씩이나 상주시키면서(?)까지 VirtualDOM을 쓰는 라이브러리 혹은 프레임워크가 많은 이유는 뭘까?.

그 이유는 '브라우저의 렌더링'과 관련이 있다. 그중에서도 '리렌더링'과 관련이 있다. interactive한 사이트에서는 유저가 버튼 하나를 눌러도 특정한 상태 변화가 생긴다. 그러면 아까 말했듯이 렌더링에 있어서 중요 역할을 하는 DOM을 직접 조작하여 결국 렌더 트리를 재구성해야하고, 리플로우, 리페인트 과정을 거쳐 최종적으로 버튼 클릭의 결과물에 따른 페이지를 유저에게 재구성해서 보여주게 된다.

이 과정에서 중요한 것은 '재구성'해서 보여주는 리렌더링 과정의 '비용 소모'이다. 앞서 말했듯이 DOM 자체의 퍼포먼스는 나쁘지 않다. 그러나, 포인트는 브라우저가 layout을 재구성하고, css를 재계산하고, 리페인트하는 과정의 시간이 오래걸리고, 퍼포먼스가 그렇게 좋지 않다. 그러면 브라우저 개발자가 브라우저 리렌더링의 퍼포먼스를 극효율화 혹은 속도 향상을 이룰 때까지(?) 우리가 할 수 있는건 뭘까(웹 개발자인 우리가)?.

결론적으로 우리가 할 수 있는 것은 '최대한 리렌더링의 발생 회수를 줄이는 것'이다. 너무나도 간단한 결론이다. 리렌더링의 시간과 퍼포먼스가 문제라면 그 리렌더링이 발생되는 회수를 줄이는 방향으로 생각하는 것이다. 하지만, 유저는 사이트에 들어와서 나무위키처럼 항상 뭔가를 읽기만하고 나가지 않는다. 버튼을 눌러보고, 스크롤링하고, 이것저것 인터랙션을 일으킨다. 따라서 우리는 이러한 유저의 인터랙션을 'batched DOM update' 방식으로 갱신해줄 필요가 있다. 즉, 100개의 조작 요청을 1번의 조작 요청으로 통합하여 100번의 리렌더링을 1번의 리렌더링(과장해보면)으로 줄여보는 것이다. 그러면 브라우저의 퍼포먼스를 향상시키지 않더라도 리렌더링의 회수 자체가 줄어서 자동으로 퍼포먼스 향상으로 이어질 것이다.

하지만 생각해보면 DOM 조작에서 배우다시피 예를 들어, ul 태그 내에 30개의 li 태그를 추가하는 작업을 for문으로 1개씩 갱신하면, 30번의 리렌더링이 일어나지만, createDocumentFragment를 이용해서 30개의 li태그에 대한 적용을 1번의 리렌더링으로 할 수 있는 것을 알고 있다. 즉, 이미 DOM을 batching해 조작할 수 있고 할 줄 안다. 그러면 도대체 scripting 시간에도 꽤나 시간을 잡아먹는(초기 로딩 속도면에서 상대적으로 느림)

** 실제로 위를 보면 라이브러리를 쓰지 않고, 렌더링한 속도가 React를 써서 렌더링한 속도보다 빠름을 볼 수 있음(hello, world를 렌더링하는 간단한 html파일로 테스트)

VirtualDOM 혹은 React 등의 프레임워크를 왜쓸까?

최종적인 결론은 '자동화 그리고 추상화'라는 키워드로 알아볼 수 있다. 먼저, VirtualDOM은 간단하게 아래와 같은 단계를 거쳐 리렌더링을 한다.

  • UI가 변경되면 전체 UI를 Virtual DOM으로 렌더링한다.
  • 현재 Virtual DOM과 이전 Virtual DOM을 비교해 차이를 계산한다(VirutalDOM은 두개가 존재한다는 의미이기도 하다).
  • 변경된 부분을 실제 DOM에 반영한다.

위의 과정을 통해서 보면 개발자가 직접 'createDocumentFragment' 등의 설계를 통해 batching 과정을 고려하지 않아도 VirtualDOM이 아예 새로 엎어버리고(?) batched 변경 사항을 새로 그려버리고, 이전의 VirtualDOM과 비교를 해서 반영하기 때문에 개발자의 노고가 줄어들고, 개발자가 해야할 일들이 '자동화' 된다. 여러개의 인터랙션을 개발자가 고려해서 직접 batching 시키는 일은 굉장히 복잡하기 때문에 이를 자동화해주는 것만해도 엄청난 일이다.

또한, domAPI를 이용해서 직접 DOM을 조작하는 이전의 방식 혹은 JQuery 등의 방식과 달리 VirtualDOM(React)이 DOM에 접근해서 최종 조작을 하기 때문에 개발자 입장에서는 DOM을 직접 조작하지 않고, 그 조작 과정이 React와 같이 개발자 편의를 도모한 라이브러리가 그 사이를 중개 혹은 추상화 해준다. 이에 따라 '추상화' 측면에서 이점이있다.

VirtualDOM vs IncrementalDOM

1) IncrementalDOM이란?

** IncrementalDOM이 리렌더링 시에 비교하는 로직을 표현한 이미지
: AngularJS는 시작부터 React와 달리 VirtualDOM이 아닌 IncrementalDOM을 채택해서 쓰고 있는데, VirtualDOM과의 차이를 통해 정의를 해보면 메모리 사용량의 측면에서의 이점을 채택하고, VirtualDOM이 채택한 속도면에서의 효율성을 상대적으로 포기한 일종의 DOM 조작 방식을 의미한다고 볼 수 있겠다. IncrementalDOM에서는 VirutalDOM 방식과는 달리 메모리 상에 따로 가상DOM을 두지않는다(이에 따라 메모리 효율성이 더 뛰어나다). 그에 따라 직접 DOM을 가지고 이전 상태와의 비교를 하여 리렌더링을 하기 때문에 속도면에서 상대적으로 떨어진다.

2) IncrementalDOM 의 장점
결론 : Incremental DOM의 이점은 메모리를 효율적으로 사용한다는 것이다.

1) 트리 쉐이킹이 가능한 Incremental DOM

트리쉐이킹 ? : 트리 쉐이킹(Tree Shaking)은 새로운 것이 아니다. 빌드 과정에서 필요로 하지 않는 코드를 제거하는 단계를 말한다.

먼저, incrementalDOM 방식에서는 자체적으로 컴파일이 가능하기 때문에(React 에서는 Webpack, babel 등의 도움을 받아서 컴파일 및 번들링이 진행됨) 트리 쉐이킹을 최대한으로 활용한다(예를 들어, svelte의 경우도 프레임워크이자 동시에 컴파일러임). 앞서 말했듯이 Incremental DOM은 컴파일 전에 명령 묶음으로 각 컴포넌트를 컴파일하고 사용하지 않는 명령을 식별하는 데 도움을 준다. 그래서 컴파일 시점에 불필요한 명령들을 제거할 수 있다. ⇒ 번들의 크기가 상대적으로 작다.

2) 메모리 사용량 감소

Virtual DOM과 Incremental DOM의 차이점을 이해하고 있다면, 메모리 사용량 감소의 비밀도 이미 알 것이다.

Virtual DOM과 다르게, Incremental DOM은 애플리케이션 UI를 다시 렌더링할 때 실제 DOM을 복사해서 생성하지 않는다. 게다가 애플리케이션 UI에 변경이 없다면 메모리를 할당하지도 않는다. 대부분의 경우, 중요한 수정 사항 없이 애플리케이션을 다시 렌더링한다. 그래서 Incremental DOM의 접근 방식은 메모리 사용을 크게 줄여준다.

그러면 IncrementalDOM이 완벽한가?

트레이드오프가 있다

Incremental DOM이 차이를 계산할 때 더 효율적인 방법을 따르기 때문에 메모리 사용량을 줄여주기는 하지만, 이 방식은 Virtual DOM보다 시간적 비용이 더 든다.

그래서 Incremental DOM과 Virtual DOM 중 결정해야 할 때, 속도와 메모리 사용량 사이에 트레이드오프가 있다.

: 생각해보면, VirtualDOM은 자체 휴리스틱 알고리즘으로 비교연산을 상대적으로(직접 DOM을 쓸 때보다) 빠르게 한다는 장점을 채택해서 쓰는 것이다. 이 때, IncrementalDOM은 이 장점이 아닌 메모리 사용상의 효율성을 채택해서 사용하는 것으로 생각하면 된다. VirtualDOM은 속도를 선택했지만 그에 따라 메모리 상에 가상DOM을 계속 상주시키는 등이 메모리적인 비효율성을 안고 가는 것.

++ IncremenatalDOM은 앞서 말했듯이 메모리 사용량과 번들 크기가 상대적으로 작기 때문에 휴대전화와 같이 메모리가 적은 장치에서 사용될 때 굉장히 좋다.

VirtualDOM의 한계 및 유의점

  • 0.1초마다 화면에 데이터가 변경된다면? Virtual DOM으로 0.5초씩 모아가지고 렌더링을 적게할 수 있을까? → 안된다. 동시에 변경되는 것에 한해서만 렌더링된다.
  • React나 Vue등을 이용해서 Virtual DOM을 쓰면 무조건 빠른가? → 아니다. 똑같이 최적화를 해야한다. (슬라이드를 옮기거나 무한 스크롤등의 움직임이 있을 때는 Virtual DOM을 이용해서 반복 렌더링을 하지 않도록 해줘야한다.)
  • Virtual DOM은 메모리에 존재한다. DOM에 준하는 무거운 객체(Virtual DOM)가 메모리에 상주(?)하고 있기 때문에 메모리의 사용이 많이 늘어날 수 밖에 없다.
  • Virtual DOM을 조작하는 것도 엄청나게 많은 컴포넌트를 조작하게 된다면 오버헤드가 생기기 마련이다. Virtual DOM 제어가 DOM 직접 제어에 비해 상대적으로 비용이 적게 들 뿐이다.

++ svelte 등의 프레임워크를 보면 VirtualDOM이 '무조건적'으로 효율적이고 퍼포먼스가 좋다고 할 수 없다. 반드시 React 등도 최적화 과정이 이뤄졌을 때 VirutalDOM을 효율적으로 쓸 수 있고, VirtualDOM이 효율적일 수 있는 사이트가 있고, svelte 혹은 angular와 같은 프레임워크가 효율적일 수 있는 사이트가 있는 것이다. 이런 부분에 대한 판단은 개발자의 몫이다.

Reference

profile
완벽함 보다는 최선의 결과를 위해 끊임없이 노력하는 개발자
post-custom-banner

0개의 댓글