Shorts
브라우저가 HTML, CSS, JavaScript를 화면에 픽셀로 그리는 일련의 작업을 CRP(Critical Rendering Path)라고 하며, 다음과 같은 과정을 거칩니다.
-
DOM 트리 구성
HTML을 파싱하여 DOM 트리를 구성합니다. HTML은 토큰화 과정을 거쳐 시작 태그, 종료 태그, 속성과 값 등의 토큰으로 변환되며, 이 토큰들은 노드로 변환됩니다. 노드가 모여 DOM 트리를 구성합니다.
HTML 파싱 중 이미지나 CSS,
async
혹은defer
속성을 가진 스크립트 등 파싱을 블로킹하지 않는 외부 자원을 만날 경우 비동기적으로 다운로드하기 시작합니다. -
CSSOM 트리 구성
CSS 파싱을 통해 CSSOM 트리를 구성합니다. 파싱과 함께 CSSOM 트리 구성은 이뤄지지만, CSS는 스타일이 스타일을 덮어씌우는 경우가 흔하므로 CSSOM이 완전히 구성될 때까지 렌더 트리에 사용될 수 없습니다.
CSS Selector는 구체적일 수록 확인할 요소가 많으므로 느려지지만, CSSOM 트리 구성 자체가 매우 빠르게 이뤄지는 작업이므로 최적화의 필요성은 낮다고 할 수 있습니다.
-
렌더 트리 구성
DOM과 CSSOM을 결합하여 렌더 트리를 구성합니다. DOM 트리의 루트부터 시작헤 눈에 보이는 요소들을 순회하며 만들어집니다.
<head>
태그의 자식 혹은display: none
인 요소처럼, 화면에 보이지 않는 노드들은 렌더 트리에 포함되지 않습니다. -
레이아웃
각 노드가 어떤 크기로 어떤 위치에 배치될지 계산하는 과정입니다. 처음 계산을 레이아웃, 이후 문서의 일부나 전체를 재계산하는 과정을 리플로우라고 합니다.
CRP에서 리플로우가 빈번하게 일어나면 성능에 악영향을 줄 수 있으므로, 박스 모델 속성은 애니메이션하지 말아야 합니다.
-
페인트
레이아웃 과정을 통해 배치한 요소들을 픽셀로 화면에 그리는 과정입니다.
서로 영향을 주지 않는 요소들을 별도의 레이어로 분리하여 그려지며, GPU를 통해 계산하여 성능을 높입니다. 이후 합성(Compositing) 과정을 통해 각 레이어를 합쳐 최종 화면을 그립니다.
URL이란 웹에서 주어진 고유 리소스의 주소를 의미합니다. 리소스를 제공하는 컴퓨터의 IP가 될 수도 있지만, 대부분의 URL은 사람이 알아보기 쉽도록 도메인 네임을 사용합니다.
브라우저는 URL로부터 프로토콜, 도메인 네임, 포트번호, 경로와 쿼리 파라미터 등을 파싱합니다. 그리고 이 도메인 네임이 가리키는 IP를 찾기 위해 다음과 같은 과정을 거칩니다.
-
hosts 파일 확인
우선 PC에 저장된 hosts 파일을 참조합니다. hosts 파일이란 IP와 도메인 네임을 매핑하는 파일로, 인터넷이 발달하기 전 초창기에 DNS 서버의 대안으로서 사용되었습니다.
-
Local DNS Cache 확인
hosts에서 도메인 네임을 찾지 못할 경우, 브라우저 혹은 운영체제의 로컬 캐시를 확인합니다. 이전에 접속한 적이 있는 사이트라면 여기서 IP 주소를 찾을 수 있습니다.
-
DNS Server Query
로컬 캐시에서도 찾지 못할 경우, DNS 서버 질의를 통해 IP를 확인합니다.
위 과정을 거쳐 해당 도메인의 IP 주소를 찾으면, 프로토콜에 따라 TCP 3-way handshake 또는 TLS negotiation 과정을 통해 네트워크 연결을 시도합니다.
연결이 성공적일 경우 GET 요청을 통해 해당 URL이 가리키는 리소스를 받아오고 이를 브라우저에 렌더링합니다.
로컬 캐시에서 도메인 네임에 해당하는 IP 주소를 찾지 못한 경우, DNS Resolver에 요청하여 IP 주소를 찾습니다.
DNS 서버는 레벨에 따라 루트 DNS 서버, TLD DNS 서버, 권한 DNS 서버로 나뉘는데, 각 DNS 서버는 자신의 하위 도메인의 주소만 갖고 있습니다. 그렇기에 DNS Resolver는 IP 주소를 찾을 때까지 루트 DNS 서버로부터 각 하위 DNS 서버로 재귀적으로 질의합니다.
예를 들어, DNS Resolver가 www.example.com
의 IP 주소를 찾는 과정은 다음과 같습니다.
-
루트 DNS 서버에
www.example.com
에 대한 IP 주소를 요청합니다..com
도메인을 관리하는 TLD DNS 서버의 주소를 반환받습니다. -
.com
TLD DNS 서버에www.example.com
에 대한 IP 주소를 요청합니다.example.com
을 관리하는 권한 DNS 서버의 주소를 반환받습니다. -
example.com
권한 DNS 서버에www.example.com
에 대한 IP 주소를 요청합니다.example.com
의 권한 DNS 서버가 CNAME 레코드로www.example.com
이example.com
을 가리킨다는 정보를 반환합니다. 즉,www.example.com
은example.com
의 별칭임을 확인합니다.이때, CNAME 레코드는
www.example.com
을example.com
으로 연결할 뿐이므로, IP 주소는example.com
의 A 레코드에서 가져오게 됩니다. -
example.com
권한 DNS 서버는example.com
의 A 레코드에 설정된 IP 주소를 확인하고, 이 IP 주소를 DNS Resolver에 반환합니다.
useEffect
란 React 컴포넌트를 외부 시스템과 동기화하는 Hook입니다.
React에 의해 제어되지 않는 외부 시스템(서드파티 라이브러리, 브라우저 API, 데이터 페칭 등)을 React의 라이프사이클과 연결하기 위해 사용합니다. 렌더링에 의해 발생하는 사이드이펙트를 다루기에 "Effect"라는 이름이 붙습니다.
useEffect
는 설정 코드(setup code)와 정리 코드(cleanup code), 그리고 의존성 리스트(list of dependencies)로 구성됩니다.
- 컴포넌트가 마운트되면 설정 코드가 동작합니다.
- 의존성 배열의 값이 변경되어 리렌더링될 경우, 정리 코드를 1회 수행 후 다시 새로운 상태값들을 반영하여 설정 코드가 동작합니다.
- 컴포넌트가 언마운트되면 정리 코드가 동작합니다. 메모리 누수나 중복 이벤트 리스너 설정 등을 방지하기 위한 코드가 포함됩니다.
- 개발 모드에서는 최초 마운트 시 설정 코드와 정리 코드가 각각 1회씩 더 동작합니다. 각각이 올바르게 작성되었는지 확인하기 위함이며, 이 과정에서 문제가 없어야 합니다.
따라서 useEffect
를 작성할 때 유의할 점은 다음과 같습니다.
- 설정 코드와 정리 코드가 올바르게 동작하도록 작성해야 합니다.
- 설정 코드의 모든 반응형 값(상태, props 등)은 의존성 배열에 포함되어야 합니다.