Rendering (브라우저, 리액트)
Browser에서 렌더링 과정
1. HTML 문서 다운로드를 합니다.
브라우저는 URL을 입력받으면 해당 페이지의 HTML문서를 서버로부터 다운로드합니다.
2. HTML 파싱(Parsing)과 DOM 트리 구성
HTML 문서를 파싱하여 DOM 트리를 구성을 합니다. DOM은 HTML 문서 구조를 트리 구조로 표현한 것입니다. 이때, HTML태그를 노드로 변환하고, 노드간의 계층 관계를 형성합니다.
3. CSS 파일 다운로드 및 스타일 정보 파싱
HTML 문서에서 CSS 파일의 링크를 찾아서 해당 파일을 다운로드하고, 파싱하여 스타일 정보를 추출하고 CSSOM구조를 생성합니다. 이때, CSS 속성을 노드로 변환하고, 노드간의 계층 관계를 형성합니다.
4. 렌더 트리 구성
DOM트리와 CSSOM트리를 결합하여 렌더트리를 형성합니다. 이때, 실제 화면에 표시될 요소만 선택하여 렌더 트리를 형성합니다.
5. 레이아웃 처리
렌더 트리의 노드가 화면의 어디에 위치해야 하는지 결정하는 레이아웃 처리가 이루어집니다.
6. 페인트 처리
렌더 트리와 레이아웃 정보를 기반으로 화면에 출력할 픽셀을 결정하고, 이를 그리는 페인트 처리가 이루어집니다.
7. 웹 페이지 출력
레이아웃 처리와 페인트 처리가 끝나면, 웹 페이지가 브라우저 화면에 출력됩니다.
이 과정에서 JavaScript 코드가 포함된 경우, JavaScript 코드는 파싱 및 실행되며, 웹 페이지의 동적인 기능을 구현합니다.
파싱(Parsing)
웹 개발에서 파싱은 웹 페이지의 HTML, CSS, JavaScript 코드를 분석하는 과정을 말합니다.
- HTML 파싱은 DOM 트리를 구성하는 과정
- CSS 파싱은 코드를 분석하여 스타일 정보를 추출하여 CSSOM 트리를 구성하는 과정
- JavaScript 파싱은 JavaScript 코드를 분석하여 실행 가능한 형태로 변환하는 과정
리플로우(Reflow), 리페인트(Repaint)
사용자가 웹 페이지에 처음 접속하게 되면, 렌더링 과정을 거쳐 화면에 모든 요소들이 그려집니다. 이후에 사용자는 다양한 액션들이 수행하게 되고, 이때 발생되는 이벤트로 인해 새로운 HTML구조가 생성되고 기존의 스타일 정보들이 바뀌거나 변경이 일어납니다. 이런 변경을 통해 영향을 받게 되는 모든 노드들에 대해 렌더 트리 생성과 레이아웃 처리 과정을 다시 하게 됩니다. 이러한 과정을 리플로우(Reflow)라고 부릅니다.
리플로우는 단순 변경사항을 반영하기 위해서 렌더 트리를 재구성하고 레이아웃 과정을 다시 수행하는 것이고, 실제 이 결과를 화면에 반영하기 위해서는 다시 페인트 처리를 해야합니다. 이러한 과정을 리페인트(Repaint)라고 부릅니다.
항상 리플로우 과정을 거쳐 리페인트 처리를 하는 것은 아닙니다. 리플로우는 실제 레이아웃에 영향이 미치면 일어고 단순 색상 변경 같은 변경사항은 리플로우 과정없이 리페인트만 수행합니다.
리플로우가 일어나는 대표적인 속성
position, width, height, margin, padding, border, border-width, font-size, font-weight, line-height, text-align, overflow
리페인트만 일어나는 대표적인 속성
background, color, text-decoration, border-style, border-radius
React에서 렌더링 과정
리액트는 가상 DOM을 사용하여 브라우저에 렌더링하는 과정을 최적화하고, 성능을 향상시킵니다.
1. 초기 렌더링
리액트 어플리케이션이 로드되면, ReactDOM.render() 함수를 호출하여 가상 DOM(Virtual DOM)을 생성합니다. 가상 DOM은 실제 DOM을 추상화한 것으로, 실제 DOM에 접근 없이 변경사항을 적용할 수 있습니다. 생성된 가상 DOM은 실제 DOM과 비교하며 변경된 부분만 갱신합니다.
2. 상태 변경
리액트 애플리케이션에서는 상태가 변경될 때마다 다시 렌더링이 발생합니다. 상태는 props와 달리 컴포넌트 내부에서 변경될 수 있습니다. 상태변경은 setState() 함수를 호출하여 이루어집니다.
3. 가상 DOM 갱신
상태 변경이 발생하면 리액트는 가상 DOM을 갱신합니다. 이때, 변경된 부분만 실제 DOM에 적용됩니다.
4. 실제 DOM 업데이트
가상 DOM을 갱신한 후 변경된 부분만 실제 DOM에 적용됩니다. 이때 DOM 업데이트는 최소한으로 이루어져 성능을 향상시킵니다.
리액트에서는 이러한 가상 DOM과 DOM 갱신 방식으로 성능을 최적화하고, 컴포넌트 단위로 모듈화하여 재사용성을 높일 수 있습니다.
Fiber
Fiber는 React v16부터 도입된 새로운 렌더링 엔진입니다. 기존의 스택 기반 렌더링 엔진 대신 Fiber는 작업 단위를 기반으로 하는 비동기 렌더링 엔진입니다.
기존의 스택 기반의 렌더링 엔진은 작업을 실행하는 동안 다른 작업을 수행할 수 없었기 때문에, 렌더링이 작업이 길어지면 길어질수록 브라우저가 느려지거나 멈추는 문제가 발생했습니다. 이를 해결하기 위해서 Fiber는 작업의 단위를 나누어 우선순위를 결정하고, 렌더링 작업을 일시 중단하거나 중단된 작업을 재실행할 수 있습니다.
Fiber의 작업 단위는 Fiber 노드라는 객체로 구성됩니다. 각 Fiber는 트리 구조를 형성하며, 부모-자식 관계와 형제 관계를 갖고 있습니다. Fiber 노드는 작업의 상태와 우선순위를 관리하며, 렌더링 작업 중에 필요한 데이터를 저장합니다.
즉, Fiber는
1. 작업을 중지하고, 필요 시 다시 시작할 수 있어야 함
2. 다른 종류의 작업들에게 우선순위를 부여할 수 있어야 함
3. 이미 완료된 작업을 재사용 할 수 있어야 함
4. 작업이 더 이상 필요 없게 되면 버릴 수 있어야 함
리액트 렌더링 프로세스
리액트에서 렌더링 프로세스는 크게 두 가지 단계, 즉 "Render Phase"와 "Commit Phase"로 나뉩니다.
Render Phase
가상 DOM을 업데이트하고 리액트 엘리먼트를 렌더링하는 단계입니다.
1. 컴포넌트 함수 호출: 리액트 엘리먼트를 렌더링하기 위해 해당 함수를 호출합니다.
2. 가상 DOM 업데이트: 호출된 컴포넌트 함수는 가상 DOM을 업데이트합니다. 이 때, 이전 가상 DOM과 현재 가상 DOM을 비교하여 변경된 부분만 업데이트합니다.
3. 업데이트된 리액트 엘리먼트 생성: 업데이트된 가상 DOM을 바탕으로 리액트 엘리먼트가 생성됩니다.
4. 엘리먼트 트리 생성: 생성된 리액트 엘리먼트들은 트리 구조로 결합됩니다.
5. 리액트 엘리먼트 렌더링: 최종적으로 트리 구조를 렌더링하여 브라우저에 표시됩니다.
Render Phase는 가상 DOM을 업데이트하고 React 엘리먼트를 렌더링하는 과정이기 때문에, 이 단계에서는 실제 DOM에는 영향을 주지 않습니다. 이후 Commit Phase에서 실제 DOM을 업데이트합니다.
Commit Phase
이전 가상 DOM과 비교하여 변경된 부분만을 실제 DOM에 적용합니다.
Commit Phase에서는 리액트 요소에서 변경된 부분을 찾아서, 해당 요소에 대한 실제 DOM 조작을 수행합니다. 이 때, 변경된 부분은 가능한 한 최소한으로 유지하여 불필요한 DOM 조작이 일어나지 않도록 합니다. Commit Phase에서는 또한, useEffect()와 같은 React Hook을 사용하여 컴포넌트의 상태 변화에 대한 작업을 처리하기도 합니다. 이 Hook을 사용하여 컴포넌트가 마운트될 때, 업데이트될 때, 언마운트될 때 등에 대한 작업을 수행할 수 있습니다.
Commit Phase는 리액트 애플리케이션의 렌더링 성능을 최적화하는 데 매우 중요합니다. Render Phase와 함께 효율적으로 구성하고 관리하여, 빠른 렌더링 속도와 높은 성능을 유지할 수 있도록 합니다.
참조
브라우저의 렌더링 과정
렌더링이란 HTML,CSS, 자바스크립트 등 개발자가 작성한 문서가 브라우저에서 출력되는 과정을 말합니다.
medium.com