Critical Rendering Path 와 Virtual DOM

jiseong·2021년 9월 13일
0

T I Learned

목록 보기
67/291

Critical Rendering Path

브라우저가 서버로부터 HTML 응답을 받아 화면을 그리기 위해 실행하는 과정을 Critical Rendering Path라고 한다.

critical Rendering Path는 다음과 같은 단계를 가진다.

1. HTML 마크업을 처리하고 DOM 트리를 생성

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="style.css" rel="stylesheet">
    <title>Critical Path</title>
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg"></div>
  </body>
</html>

2. CSS 마크업을 처리하고 CSSOM 트리를 생성

body { font-size: 16px }
p { font-weight: bold }
span { color: red }
p span { display: none }
img { float: right }

3. DOM 및 CSSOM을 결합하여 Render Tree 생성

4. Render Tree에서 Layout(또는 Reflow)을 실행하여 각 노드의 기하학적 형태를 계산함

해당 과정에서 %, vh, vw와 같이 상대적인 위치, 크기 속성은 모두 실제 화면에 그려지는 px단위로 변환된다.

5. Render Tree의 각 노드를 painting하여 화면에 나타냄

해당 과정을 거치고 나면 비로소 화면에 나타나게 된다.

위의 과정을 하나의 그림으로 표현하면 아래와 같다.

하지만 여기서 우리가 자바스크립트를 통해 DOM을 조작하면 보통의 경우 DOM tree를 수정하게 된다. 그렇게되면 render tree - Layout - Painiting의 단계를 또 다시 겪게 되는데 이는 많은 비용이 들며 속도 저하의 주요 원인이 된다.

render blocking & Parser blocking (리소스)

HTML 파일에서 스타일을 적용하는 방법에는 여러가지가 있다.
그 중에서 브라우저는 <style /> 또는 inline style 블럭을 발견했을 때는 CSS 구문을 분석 후 CSS 규칙을 이용해서 CSSOM 트리를 업데이트 후 HTML 파싱을 재진행

그러나 외부 stylesheet는 다른 방식으로 동작된다. 외부 stylesheet는 Parser blocking요소가 아니기 때문에 메인 스레드가 아닌 백그라운드에서 다운로드하기 때문에 파싱을 멈추지 않는다.

  • css는 render blocking ( render tree를 만들 때 CSSOM이 필요하기 때문에
    {cascading 때문에 css는 점진적으로 CSSOM 트리를 만들 수 없고 CSS를 모두 해석해야 구성할 수 있다.})

  • javascript는 Parser blocking ( async나 defer 옵션을 준다면 실행되는 순서를 늦출 수 있다.
    async: 다운은 병렬적으로하고 다운이 완료되면 dom parsing을 blocking
    defer: 다운은 병렬적으로하고 다운이 완료되더라도 dom parsing을 blocking하지 않고 끝날 때까지 기다림)

Reflow & Repaint

자바스크립트에 의해 DOM 트리, CSSOM 트리가 변경될 때 Render Tree가 다시 재구성되며 Reflow와 Repaint가 일어나게 된다. (위에서 언급된 Layout의 과정부터 다시 시작)

기하적인 영향을 주지 않는 CSS 속성값을 변경하면 Layout 과정은 건너뛴다.

Layout이 일어나면 전체 픽셀을 다시 계산해야 하므로 부하가 크다. 반면, Repaint는 이미 계산된 픽셀값을 이용해 화면을 그리기 때문에 Layout에 비해 부하가 적다.

다음과 같은 코드가 있다고 가정해보자.

<div id="sample" style="background:red;width:150px;height:50px;">
  Sample
</div>

요소에 기하적인 영향을 주는 CSS 속성값에는 height, width, left, top, font-size, line-height 등이 존재하며 해당 속성을 이용해서 CSSOM 트리를 변경하게 되면 다음과 같이 Layout이 발생한 것을 볼 수 있다.

const example = document.getElementById('example');

example.style.width = '400px';

Layout 발생

요소에 기하적인 영향을 주지 않는 CSS 속성값에는 background-color, color, visibility, text-decoration등이 존재하며 해당 속성을 이용해서 CSSOM 트리를 변경하게 되면 다음과 같이 Layout은 건너뛰고 Paint만 발생하는 것을 볼 수 있다.

const sample = document.getElementById('example');

example.style.backgroundColor = 'blue';

리페인트 발생

React와 Virtual DOM

React는 SPA이기 때문에 DOM을 조작하는 경우가 많아 위와 같은 이슈를 겪게 된다. 그래서 해당 이슈를 해결하고자 Virtual DOM을 사용한다.

React의 공식문서에 따르면 Virtual DOM은 이상적인 또는 "가상" UI 표현이 메모리에 유지되고 ReactDOM과 같은 라이브러리에 의해 "실제" DOM과 동기화되는 프로그래밍 개념이라고 한다.

Virtual DOM을 사용하면 다음과 같은 장점이 존재한다.

Batch Update

화면에 변경사항들이 발생했을 때 Virtual DOM에서 Batch단위로 처리하여 나온 최종적인 결과를 실제 DOM에게 전달하기 때문에 불필요한 연산의 횟수를 줄일 수 있다.

즉, 한번의 렌더링만으로도 되는 과정에서 여러 곳이 바뀌면서 여러번 렌더링 할 때 효율적으로 한번의 업데이트를 하는 방법을 제시해준다. (DOM이 빈번히 업데이트하는 것을 좀 더 효율적인 방법으로 업데이트)

하지만 이러한 과정은 Virtual DOM 없이도 변화가 있을 때마다 그 변화들을 묶어 DOM fragment에 적용하여 실제 DOM에 전달하여도 불필요한 연산의 횟수를 줄일 수 있으며 Virtual DOM은 DOM보다 빠르다고도 할 수 없다.

그럼에도 Virtual DOM을 사용하는 이유는 매번 어떤 DOM 노드가 변경되어야하는지 파악해야하고 조작 할 DOM이 많아지게 되면 실수가 발생할 가능성도 커지는데 Virtual DOM은 이러한 복잡한 과정들을 자동화 및 추상화 해주기 때문에 사용한다고 할 수 있다.


Reference

0개의 댓글