[ React의 모든 것 ] 01. DOM과 Virtual DOM, 그리고 CDN
도입
본격적인 학습에 들어가기 이전 Codesandbox를 활용하여 간단하게 리액트 CDN(Contents Delivery Network)을 사용해 h1 태그(Tag)를 만들어봤다.
해당 강의에서 DOM(Document Object Model)과 CDN(Contents Delivery Network)에 대한 언급이 있었는데, 강의에서는 자세히 다루지는 않았으나 한 번 정리를 하고 넘어가면 좋을 것 같아서 이렇게 글을 작성했다. 사용된 코드는 맨 아래 깃헙 레포지토리에서 확인할 수 있다.
DOM
DOM(Document Object Model)은 단어 그대로 문서 객체 모델을 의미한다. 여기서 문서(Document)는 웹 페이지를 의미한다고 생각하면 편하다. 그러면 이를 다시 한 번 풀어서 설명하면, 웹 페이지를 하나의 객체 모델로 만든 것을 DOM이라고 하는 것이다.
그렇다면 객체는 무엇을 의미할까? 객체(Object)는 보통 사물들을 의미한다. 다시 말해 인식할 수 있는 것이라 생각하면 편한데, 이를 토대로 DOM의 의미를 풀어서 생각해보면 웹 페이지를 하나의 이해할 수 있는 모델로 만드는 걸 의미한다.
이를 조금 더 확장해서 과연 누가 이해할 수 있는 모델로 만드는지 생각해볼 수 있다. HTML은 보통 <h1></h1> 과 같이 요소(Element)의 집합으로 구성되어 있다. 이러한 집합을 자바스크립트가 이해할 수 있는 객체로 만들어주는 것이다. 이를 통해 기존 HTML 코드로 작성하던 요소들을 자바스크립트를 통해 접근하고 제어할 수 있게 된다.
그렇다면 자바스크립트가 이해할 수 있게 되면서 얻게 되는 장점은 무엇일까? 우선 개발자들 사이에서 유명한 농담인 "HTML is a programming language"를 한 번 생각해보자.
HTML은 프로그래밍 언어가 아니다. 이를 조금 더 구체적으로 생각하면, 우리가 흔히 자바스크립트 또는 파이썬과 같은 프로그래밍 언어를 통해 구현하던 로직들을 만들 수 없다는 의미다. 조금 더 구체적인 설명을 위해 아래 웹 페이지를 한 번 봐보자.
반복되는 div 태그를 5개 만드려고 한다. HTML 코드만을 사용해서 이를 만들면 아래와 같이 만들 수 있다.
그런데 만약 이러한 반복되는 태그가 1,000개 이상이 필요하다고 생각해보자. 하나씩 복사-붙여넣기를 하기에는 너무 비효율적이다. 이를 자바스크립트를 통해 DOM을 조작해서 만들면 아래와 같이 간단하게 만들 수 있다.
우선 반복되는 div 태그를 감쌀 부모 태그를 하나 만들고 id 를 vanila 라 지정한다.
그리고 getElementById 메서드를 통해 해당 태그에 접근한 다음 createElement , textContent , appendChild 메서드를 통해 태그에 원하는 내용을 입력할 수 있다. 그리고 이를 for 반복문을 활용해서 원하는 만큼 반복할 수 있다. 결과적으로 HTML만을 사용했을 때보다 훨씬 효율적으로 작업할 수 있게 된 것이다.
이처럼 웹 페이지를 하나의 객체로 만들어서 자바스크립트 등의 프로그래밍 언어를 통해 접근하여 제어할 수 있게 하는 게 바로 DOM이다. 이를 통해 우리는 훨씬 효율적이고 확장성 좋은 애플리케이션을 개발할 수 있다는 사실을 쉽게 추론할 수 있다.
DOM 트리
우리가 흔히 DOM에 관해서 이야기할 때 '트리(Tree)'라는 용어가 함께 사용된다. DOM이 트리 구조로 되어 있기 때문이다. 그렇다면 트리 구조란 무엇을 의미할까?
트리는 단어 그대로 나무를 떠올리면 쉽다. 나무는 뿌리-기둥-줄기-가지 순서로 뻗어나간다. 부모인 뿌리를 기준으로 하나씩 생성되어 점점 파생되어 가는 구조인데, 이처럼 일종의 계층을 가진 구조를 트리 구조라 한다. 특징으로는 원형이 되는 부모(Parent)와 그 부모로부터 파생된 자식(Children)이 존재한다는 점이다.
DOM도 마찬가지다. HTML 파일을 만들어보면 알겠지만 그 구조는 <html></html> 이라는 루트 요소 안에 <head></head> 라는 헤드 요소와 <body></body> 라는 바디 요소로 구성되어 있다. 그리고 헤드 요소에는 웹 페이지와 연관되어 있는 여러 메타데이터(Metadata) 정보들이 입력되고, 바디 요소에는 실질적으로 브라우저 상에 보여질 콘텐츠가 입력된다. 이를 쉽게 표현하면 아래 이미지와 같다.
앞선 자바스크립트 코드에서도 vanlia 라는 id 를 가진 div 태그에 접근하여 해당 태그를 부모 요소(Parent Element)로 가지는 자식 요소(Child Element)를 appendChild 메서드를 통해 구현한 것이다. 중요한건 이때 각각의 개별적인 요소를 하나의 노드(Node)라고 부른다.
BOM
BOM(Browser Object Model)이라는 것도 존재한다. BOM은 문자 그대로 브라우저 객체 모델을 의미하며, 이를 통해서 웹 브라우저(WEB Browser)와 관련된 기능을 구성한다. BOM의 최상위 객체(Object)는 Window 인데 DOM과 BOM은 이 Window 객체를 상속 받는다. 이러한 객체 관계를 쉽게 아래와 같은 이미지를 통해 나타낼 수 있다.
CDN
리액트를 별도로 설치하지 않고 간단하게 테스트를 위해 사용하려면 리액트 CDN(Contents Delivery Network)을 이용하면 된다.
CDN Links – React
A JavaScript library for building user interfaces
reactjs.org
그렇다면 CDN은 도대체 무엇이기에 별도의 설치 없이 리액트 사용을 가능하게 만들어주는 것일까? CDN은 용어 그대로 콘텐츠 전송 네트워크를 의미한다. 여기서 콘텐츠는 이미지, HTML, CSS 등을 의미한다. 다시 말해 이미지, HTML, CSS 등을 전송해주는 네트워크를 의미하는데, 이미 콘텐츠를 전송해주는 서버가 서브스마다, 또는 웹 페이지마다 따로 존재할 텐데 어째서 CDN이 별도로 존재하는지 궁금할 수 있다. 그 이유는 CDN의 목적이 바로 위에서 언급한 컨텐츠를 캐싱하는데 있기 때문이다.
이미지, HTML, CSS 등을 정적 컨텐츠(Static Contents)라 한다. 여기서 '정적(Static)'이란 용어의 의미는 말 그대로 변화가 없다는 걸 의미한다. 따라서 정적 콘텐츠는 미리 저장하여 요청(Request)에 따른 응답(Response)만 바로 해주면 되는, 별도의 맞춤형 전략이 필요 없는 콘텐츠를 의미한다. CDN은 이러한 정적 콘텐츠를 캐싱하는데 목적이 있다. 여기서 캐싱(Cashing)이란 쉽게 더 빠르게 연산을 처리하기 위해 데이터를 미리 기억해놓는 걸 의미한다.
예를 들어 한국 부산에서 미국 캘리포니아에 위치한 서버에 요청을 보내서 응답을 받는다고 생각해보자. 쉽게 부산에서 미국의 웹 페이지를 여는 것이다. 그러면 물리적으로도 서로 먼 거리에 위치해있기 때문에 콘텐츠를 불러오는 데 지연(Delay)이 발생할 수 있다. 이런 경우 바로 CDN을 사용할 수 있다. 해당 콘텐츠를 한국의 서울 서버에 캐싱하여 요청할 때 미국으로 보내는 것이 아닌 서울로 보내 빠르게 응답을 받을 수 있게 된다.
결론적으로 CDN을 사용하여 여러 요청이 분산되어 트래픽(Traffic)을 어느 정도 원활하게 할 수 있으며, 콘텐츠 전달 속도 자체도 빨라지게 된다. 다시 말해 콘텐츠 제공에 안정성이 생긴다.
리액트 CDN
아래와 같이 리액트 CDN에서 제공한 코드를 입력해서 간단하게 리액트를 사용할 수 있다.
이제 간단하게 리액트를 사용하여 <h1></h1> 를 삽입해보자. 먼저 <h1></h1> 요소가 삽입될 부모 요소(Parent Element)인, react 라는 id 를 가진 div 태그를 하나 만든다.
방법은 자바스크립트와 거의 동일하다. 아래 이미지를 한 번 살펴보자. getElementById 를 통해 해당 부모 요소를 가져온 다음, React 의 createElement , ReactDOM 의 render 메서드를 활용해 해당 <h1></h1> 요소를 만들 수 있게 된다.
createElement 는 앞서 자바스크립트에서 document 객체를 통해 사용한 메서드 createElement 와 유사하다. 그렇다면 과연 render 는 무엇일까? 이에 관해 알기 위해서는 ReactDOM , 다시 말해 Virutal DOM에 관해 먼저 알아봐야 한다.
Virtual DOM
우선 Virtual DOM의 관해 살펴보기 이전 간단하게 리액트 공식 문서 Rendering Elements에 나온 예시를 한 번 살펴보자.
Rendering Elements – React
A JavaScript library for building user interfaces
reactjs.org
아래 이미지와 같은 리액트 코드를 사용해 간단한 시계를 만든다.
그리고 이와 동일하게 동작하는 자바스크립트 코드를 아래와 같이 만든다.
이를 아래 이미지와 같이 개발자 도구에서 엘리먼트의 변화를 살펴보면 자바스크립트로 만든 코드의 경우 div 태그와 h2 태그가 함께 변경되고, 리액트로 만든 코드의 경우 h2 태그만 변경되는 것을 확인할 수 있다.
주의
해당 코드를 직접 CDN을 사용해 테스트해보고 싶다면 아래와 같이 babel 을 추가해줘야 합니다.
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
또한 해당 리액트 코드를 작성한 <script></script> 요소의 type 을 "text/babel" 로 지정해줘야 하며 'use strict' 를 제일 상단에 작성해줘야 합니다. 관련된 내용은 다루지 않으니 참고를 원하시는 분들은 맨 아래 깃헙 레포지토리에서 코드를 확인해보기 바랍니다.
Virtual DOM은 결국 DOM을 가상으로 만들어 변화되는 부분만 수정해준다. 리액트 공식 문서 속 Virtual DOM and Internals에는 virtual DOM에 관해 아래와 같이 설명하고 있다.
Since "virtual DOM" is more of a pattern than a specific technology, people sometimes say it to mean diffrent things. In React world, the term "virtual DOM" is usually associated with React elements since they are the objects representing the user interface.
쉽게 설명하면 어떤 기술이 아닌 패턴을 의미한다는 뜻이다. 결론적으로 리액트에서는 이 용어가, DOM은 결국 객체를 의미하기 때문에 리액트 요소(React element)와 연관되며 이때 이것이 어떤 세부적인 기술이라기 보다는 패턴을 의미한다는 뜻이다.
그렇다면 기술이 아닌 패턴을 의미한다는 게 무엇일까? 이와 관련해서는 Hashnode에 Sai Kishore Komanduri가 작성한 아티클 The one thing that no one properly explains about React - Why Virtual DOM을 읽어보면 더 이해하기 쉽다.
The one thing that no one properly explains about React — Why Virtual DOM - Hashnode
The other day a friend had this React question for me: “Composition through components, one way data binding; I understand all that, but why Virtual DOM?”. I’ve given him the usual answer. "Because, direct DOM manipulation is inefficient, and slow."
hashnode.com
해당 아티클에서 핵심이 되는 문장은 바로 다음과 같다.
But Actually, this particular behaviour can be achieved without a virtual DOM. You can manually group all the DOM modifications in a DOM fragment yourself and then dump it into the DOM.
So, again, what does a Virtual DOM solve? It automates and abstarcts the management of that DOM fragment so you don't have to do it manually.
쉽게 설명하자면 Virtual DOM이 하는 일은 기술적으로 엄청나기 보다는 사실 우리가 직접 할 수 있는 작업들인데 자동화(automates)와 추상화(abstracts)를 통해 우리가 수동으로 해야하는 작업을 대신 해준다는 것이다. Virtual DOM과 추후 배우겠지만 컴포넌트(Component) 등을 통해 결국 리액트로 얻어갈 수 있는 장점은 사실 속도라기 보다는 유지보수이고, 이러한 맥락에서 Virtual DOM은 어떤 기술이라기 보다는 패턴을 의미하는 것이다.
Virtual DOM의 동작 방식에 관해 조금 더 확실하게 이해하기 위해서는 우선 DOM의 동작 방식을 이해할 필요가 있다. 위 아티클에 나온 DOM 동작 방식을 한 번 살펴보자. 이를 직관적으로 표현하면 아래 이미지와 같다.
위와 같은 과정을 렌더링(Rendering)이라고 한다. 렌더링은 쉽게 개발자가 HTML, CSS, JavaScript 등을 활용하여 만든 문서를 브라우저 상에서 가시적으로 화면에 나타내주는 작업을 의미한다.
우리가 해당 과정에서 살펴봐야 할 부분은 바로 어테치먼트(Attachment)다. HTML을 파싱(HTML Parser)하여 DOM을 생성하고, CSS를 파싱하여(CSS Parser) 스타일 규칙(Style Rules)을 만든 다음 이 둘을 합치는, 다시 말해 어테치먼트(Attachment)하여 렌더 트리(Render Tree)를 생성하고 이를 기준으로 레이아웃(Layout)을 배치하고 그린다(Painting). 그러고나면 실제 사용자가 브라우저에서 마주하는 화면이 보여지는(Display) 것이다.
이때 어테치먼트(Attachment) 과정에서 HTML 또는 CSS에 변화가 발생하면 다시 어테치먼트(Attachment)를 실행하여 렌터 트리(Render Tree)를 재생성한다. 결국 작은 변화에도 매번 렌더 트리를 재생성해야 하기 때문에 매우 비효율적인 것이다.
잠깐!
물론 브라우저가 100번 변경된다고 무조건 100번 렌더링 되지는 않는다.
렌더링 과정 자체에서도 배치(Batch) 작업을 통해, 다시 말해 실시간이 아닌 일괄적으로 모아서 작업을 처리해서 어느 정도 효율성을 높이려고는 한다. 그래도 여전히 비효율적이다.
이때 Virtual DOM을 사용하면 이 가상화된 DOM이 중간에서 먼저 수정되고 이를 통해서 DOM이 수정된다. 이를 조금 더 풀어 설명하자면, Virtual DOM에 변경 내역을 한 번에 모으는 버퍼링(Buffering) 작업이 들어가고 해당 변경 내역을 DOM과 비교하여 변경된 부분을 통해 렌더링을 한 번만 하게 하는 것이다. 비교를 할 때는 내부적으로 재조정(Reconciliation) 작업을 거친다. 일종의 내부적인 알고리즘을 통해 효율적으로 차이점을 비교하는 것인데 props 등의 여러 개념을 추가적으로 알아야 해서 관련해서는 다음에 자세히 한 번 설명해보려 한다. 관련 내용은 아래 글을 확인하면 된다.
Reconciliation – React
A JavaScript library for building user interfaces
reactjs.org
어쨌든 이러한 비교를 통해 결국 Virtual DOM은 효율적인 렌더링을 구현하는데 Virtual DOM 자체도 결국 메모리에 존재하는 개념이기 때문에 메모리 사용량이 늘어날 수 없다. 더욱이 자바스크립트 엔진은 나날이 발전하고 있기 때문에 무조건적으로 리액트를 사용하는 게 자바스크립트보다 훨씬, 다시 말해 Virtual DOM이 DOM 보다 더 빠르다고 볼 수 없다.
그렇다면 Virtual DOM을 써야하는 이유는 뭘까? 변경되는 부분만을 다룬다는 개념은 다시 말하면 DOM에 대한 조작의 용이성을 의미한다. 개발자가 DOM을 조금 더 자유롭게 조작할 수 있기 때문이다. 더욱이 일관된 구조(Structure)를 가져갈 수 있는 큰 장점이 있다. 관련해서는 추후 컴포넌트(Component) 등을 배우면 더 몸소 느낄 수 있다.
결론
이번에 DOM(Document Object Model), Virtual DOM, 그리고 CDN(Contents Delivery Network) 개념에 관해 알아봤다. 그리고 이 과정에서 직접 바닐라 자바스크립트 코드로 짜여진 것과 리액트 코드로 짜여진 것의 차이점을 보며 DOM과 Virtual DOM의 차이는 물론 결론적으로 Virtual DOM을 사용하는 이유, 다시 말해 바닐라 자바스크립트가 아닌 리액트로 애플리케이션을 만드는 이유에 관해서 고찰해봤다. 이를 한 문장으로 정리해보면 아래와 같다.
Virtual DOM은 DOM 만큼 충분히 빠른 속도를 내면서 더 효율적으로 DOM을 관리할 수 있게 해주기 때문에 큰 규모의 애플리케이션을 구축하고 유지보수할 때 유용하다.
참고
https://fastcampus.co.kr/dev_online_react
한 번에 끝내는 React의 모든 것 초격차 패키지 Online. | 패스트캠퍼스
20가지 이상 관련 스택으로 제대로 잡는 React! 7가지 실무 필수 기능을 각각 구현하고, 유기적인 연결성을 이해할 수 있는 대규모 서비스 클론 코딩까지 진행하세요! 자유도가 높은 React, 100% 활용
fastcampus.co.kr
코드
https://github.com/0417taehyun/all-about-react
GitHub - 0417taehyun/all-about-react
Contribute to 0417taehyun/all-about-react development by creating an account on GitHub.
github.com