-
11/15 TIL | React의 Virtual DOM은 과연 빠른가?📝 기록/매일의 기록 2022. 11. 15. 13:08
어제 작성한 TIL은 React Virtual DOM의 재조정(Reconsiliation)에 대한 내용으로 React가 보다 더 효과적으로 DOM을 갱신하기 위해서 채택하고 있는 내부 방식에 대해 정리하였다.
홀맨님께서 이 TIL을 보시고는 코멘트 달아주셨는데 내용은 아래와 같다.
요약하자면 Virtual DOM가 수반하는 오버헤드가 상당하기 때문에 요새는 Virtual DOM을 사용하지 않는 기술들이 나오고 있다는 것!! 사실 요새 Svelte(스벨트)를 사용하는 사람들이 점점 많아진다는 것을 느끼긴 했지만 Svelte가 어떤 설계로 이루어져, 어떤 강점을 가지고 있는지는 전혀 모르고 있었기에 이렇게 말이 나온 김에 한번 오늘 TIL로 이 내용들을 정리해보기로 결심하였다!
🧐 Virtual DOM의 오버헤드는 어디에서 오는가?
💡 오버헤드(Overhead)란?
어떤 처리를 하기 위해 들어가는 간접적인 처리 시간 및 메모리 등을 말한다.
우선 React는 대규모 애플리케이션을 만들기 위해 만들어졌다. 때문에 브라우저의 reflow와 repaint 과정을 최소화하려 노력하였는데, 이러한 노력은 Virtual DOM의 Diffing(비교) 알고리즘으로 구현할 수 있었다.(참고로 브라우저 렌더링 과정은 이번 주에 작성할 예정!)Virtual DOM의 DOM 트리는 메모리상에 존재하며, DOM fragment를 관리하는 과정을 자동화하고 추상화한다. Diffing 알고리즘은 Virtual DOM과 실제 DOM의 차이를 비교하여 수정해야 하는 부분만 수정하고, 연산이 끝나면 수정이 반영된 DOM 트리를 브라우저 레이아웃 엔진에 건네주어 한 번의 reflow와 repaint 과정이 처리되도록 한다. 이 과정을 reflow, repaint 과정의 최소화라고 보는 것이다
React의 Virtual DOM에서 사용하는 Diffing 알고리즘은 분명 빠르다. 다만 오버헤드는 컴포넌트 자체에서 온다.
function Component(props) { const [selected, setSelected] = useState(null); return ( <div> <p>Selected {selected ? selected.name : 'nothing'}</p> <ul> {props.items.map(item => <li> <button onClick={() => setSelected(item)}> {item.name} </button> </li> )} </ul> </div> ); }
위와 같은 컴포넌트가 있다고 가정해보자. 각각 이벤트 핸들러를 가지고 있는 <li> 태그들이 있다고 했을 때, props.items이 변경되는 것과 관계없이 상태가 변경될 때마다 <li> 태그들이 새롭게 생성된다. 만약 우리가 퍼포먼스에 그렇게 신경 쓰지 않는 한, 아마도 이 코드의 성능을 최적화하진 않을 거다. 그럼에도 불구하고 이 코드는 여전히 빠른 속도이기 때문이다.
하지만 이렇게 불필요한 작업들을 리스크로 가지고 있을 경우, 사소한 코드라도 최적화해야 하는 순간이 오게 됐을 때 이러한 병목 현상들로 앱이 죽을 수도 있다는 것이다. Virtual DOM을 이전 스냅샷과 먼저 비교하지 않고는 실제 DOM에 변경사항을 적용할 수 없기 때문에 Diffing은 결코 무료가 아니라는 것이다. 그렇기 때문에 Virtual DOM을 쓰면 무조건 빠른 것이 아니라 실제 DOM을 쓸 때와 똑같이 최적화를 해줘야 하는 것이다. (예를 들어 무한 스크롤 기능을 구현하게 된다면, 반복 렌더링이 되지 않게 미리 작업을 해줘야 한다!)
이와 관련된 Dan Abramov(a.k.a Redux의 창시자 & React 개발자)의 트윗을 가져왔다. 해석해보자면, React가 DOM보다 빠르다는 것은 잘못된 사실이고, 실제로는 유지 보수가 가능한 애플리케이션을 만드는 것을 React가 도와주고 대부분의 경우에서 Virtual DOM은 *충분히 빠르다*는 것이다.
흔히들 React는 빠르다라고 생각하는데, 실제 최적화 작업을 직접 한다고 했을 때 대부분의 경우 React를 사용한 것보다 직접 구현한 것이 빠르다고 한다. 다만 이를 자동화해주는 라이브러리인 React를 사용하게 되면 생산성이 높아지는 것! 그렇기에 React는 개발과 유지보수가 편해서 쓰는 것이지, 무작정 바닐라 JS보다 빠르다는 것은 아니라는 것이다.
🔍 Virtual DOM을 사용하지 않는 프레임워크: Svelte
그렇다면 Virtual DOM을 사용하지 않는 프레임워크인 Svelte(스벨트)에 대해서 알아보자! Svelte는 Diffing하는 과정과 그로부터 파생되는 오버헤드가 없고, 실제 DOM을 갱신하는 역할만 있기 때문에 리소스를 아끼고, 빠른 성능을 낼 수 있다고 한다. 그렇다면 Virtual DOM 없이 Svelte는 어떻게 변경된 부분을 판단할 수 있는 걸까?
이는 자바스크립트 자체의 반응성을 활용하고 있기 때문이다. 이때, 반응성이란 애플리케이션의 상태, 즉 데이터의 변화가 DOM에 자동으로 반응되는 현상을 말한다. Svelte는 빌드 시 실행되어 구성요소(DOM)를 업데이트하는 명령형 코드로 컴파일한다(참고로 리액트와 뷰는 선언형). 때문에 Virtual DOM을 사용하지 않고도 순수 자바스크립트로 결과물을 만들고, 그 결과물을 브라우저에 동작시킴으로써 브라우저 성능을 최적화하고 반응성도 유지할 수 있는 것이다!
참고
React와 Vue만 써본 입장으로 나는 Virtual DOM의 좋은 점만 바라봤었는데, 이렇게 알아보니 Virtual DOM이 모든 문제의 해결사는 아니라는 것과 React를 사용할 때 그 작동 원리를 제대로 이해하지 못한 채로 사용하게 된다면 오히려 엄청 좋지 못한 퍼포먼스를 만들 수도 있다는 것을 깨달았다. 결론적으로 모든 이론을 관통하는 것은 뭐든지 원리를 제대로 알고 사용해야 한다는 것이다! 오늘도 이렇게 하나 더 배웠다!🤗
'📝 기록 > 매일의 기록' 카테고리의 다른 글
11/17 TIL | React 성능 최적화 1탄. React.memo & React.PureComponent (0) 2022.11.17 11/16 TIL | React 상태 관리 라이브러리 useStore-ts! 마이크로스토어로 가는 길🚶🏻♀️ (2) 2022.11.16 11/14 TIL | React Virtual DOM의 재조정(Reconsiliation) (0) 2022.11.14 11/13 TIL | Flux 패턴이란? (0) 2022.11.13 11/12 TIL | 나만의 메뉴 만들어보기. (0) 2022.11.12