문서/기타

브라우저가 웹 페이지를 표시하기 까지

뇽원 2024. 7. 15. 07:36


Prologue
지금까지 웹 프론트엔드 개발을 공부하면서, 웹 사이트를 설계하고 개발하는 것만 배웠지 근본적으로 브라우저가 웹 사이트를 받아오고 그려오는 과정에 대해서는 모르고 있었다.

사실 무엇을 시작하던 기초적인 바탕 개념이 있어야 이를 응용하여 발전해 나갈 수 있는 것처럼, 웹 개발을 공부하면서 고차원적인 CS 지식들이 요구되는 개념들이 등장함에 따라 브라우저가 웹 페이지를 표시하기까지의 모든 과정을 간단하게 톺아보기로 결심했다.

MDN Web Docs에서 위 과정을 상세하게 설명해 주어서, 위 문서를 바탕으로 내용을 정리하였다.

잘못된 내용 제보 환영합니다.



1. 탐색 (Navigation)
우리가 일반적으로 검색창에 URL을 입력하거나 링크를 클릭하면, 브라우저는 서버로부터 GET 요청을 보내게 된다.

이 과정에서 브라우저는 URL의 DNS를 탐색하고 서버의 주소를 알아낸다. 서버의 아이피를 그대로 작성하게 된다면 이 과정은 생략될 수 있지만, 대부분의 웹 사이트의 경우 도메인을 통해 서버 주소를 숨기고 있기 때문에 이 과정은 생략되기 어려울 것이다.

처음 특정 웹 사이트를 접속하게 되면, 해당 서버 주소는 일정 기간 동안 브라우저 내에 캐싱(저장)된다. 따라서 웹 사이트를 매번 접속할 때마다 DNS를 통해 서버 주소를 알아내지 않아도 된다.

그리고 브라우저는 서버와의 연결을 성립시키기 위하여 TCP 핸드셰이크를 수행한다. 이때 브라우저와 서버는 SYN, SYN-ACK, ACK 메시지들을 주고받으면서 TCP 소켓 연결을 확인하고, 이상이 없으면 연결한다.

이후 추가적으로 TLS 핸드셰이크를 진행한다. 보통 SSL이라고 불리는 TLS 핸드셰이크는 HTTPS 연결을 사용하기 위해 클라이언트와 서버 간 무결성을 확인하고 암호키를 주고받는다.

출처: MDN Web Docs



2. 응답 (Response)
위와 같이 연결 성립 및 무결성 검증 등이 완료가 되면, 브라우저는 GET 요청을 통해 서버로부터 HTML 파일을 요청한다. 서버는 이 요청을 확인하고 이상이 없으면 상태 코드와 관련 응답 헤더와 함께 리소스들을 전달한다.
 
상태 코드는 수신받은 HTTP 요청에 대해 서버의 처리 상태를 의미한다. 응답 헤더는 서버가 응답하며 같이 참조되는 데이터이며, 서버의 정보 및 상태 등을 포함한다.
HTTP 상태코드가 의미하는 바는 다음과 같다.

1XX (정보): 요청을 받았으며 프로세스를 계속한다.
2XX (성공): 요청을 성공적으로 받았으며 인식했고 수용하였다.
3XX (리다이렉션): 요청 완료를 위해 추가 작업 조치가 필요하다.
4XX (클라이언트 오류): 요청의 문법이 잘못되었거나 요청을 처리할 수 없다.
5XX (서버 오류): 서버가 명백히 유효한 요청에 대해 충족을 실패했다.
출처: 위키피디아


3. 구문 분석 (Parsing)
서버로부터 성공적으로 HTML 데이터를 받아오면, 브라우저는 받아온 데이터로 DOM 트리와 CSSOM 트리를 생성한다. 이는 브라우저가 페이지를 렌더링 할 때 사용된다.

DOM(Document Object Model): HTML 요소를 구조화시킨 것으로, HTML 요소와 상호작용하고 표현하는 API이다. 여러 프로그램이 페이지의 콘텐츠 및 구조, 그리고 스타일을 읽고 조작할 수 있도록 해준다.
CSSOM(CSS Object Model): 스타일시트 정보를 읽고 표현하기 위한 API이다. DOM과 비슷하게 작동한다.

 
첫 번째로 브라우저는 구문 분석기를 이용하여 HTML 데이터를 토큰화하여 이를 분석하고, DOM 트리를 생성한다. 이때 구문 분석기는 이미지나 CSS 파일과 같은 파일들을 발견하면 이를 서버에 요청하고 구문 분석을 계속 진행한다. 하지만 async/defer 같은 설정이 되어있지 않은 script 태그는 렌더링을 막고, 구문 분석기의 작업을 중지시킨다. 이때, 프리로드 스캐너가 개입하게 된다.
 
프리로드 스캐너(Preload Scanner)는 구문 분석기가 HTML을 분석하기 전에, 먼저 HTML 파일을 전반적으로 훑어보며 우선순위가 높은 자원들을 우선적으로 요청해 준다. 이 덕분에 구분 분석 중 별도의 자원 요청으로 인한 분석 지체가 줄어든다.
 
두 번째로 CSSOM 트리를 생성한다. 위 설명과 같이 CSSOM은 DOM과 비슷한 구조를 띄고 있지만, DOM 트리 생성에 소요되는 시간보다 매우 짧은 생성 시간을 가진다.
 
추가적으로, Javascript 파일이 제공되면 브라우저는 Javascript의 해석 및 컴파일, 구문 분석을 수행하고 이를 실행한다. 그리고 보조 장치 등이 DOM 내용을 분석하고 해석하기 위해 접근성 트리를 구축한다. 



4. 렌더 (Render)
위 과정에서 생성된 DOM트리와 CSSOM 트리를 이용하여, DOM 트리의 루트부터 시작해 화면에 나타나는 태그들을 순차적으로 순회하며 렌더 트리를 생성한다. 이 과정을 스타일(Style)이라고 한다.
 
렌더 트리 생성 이후, 레이아웃(Layout) 과정에서 렌더 트리의 루트부터 순회하며 각 노드의 위치 및 크기 등을 결정한다. 이후 필요에 따라 노드의 크기와 위치를 다시 계산하게 되는데, 이를 리플로우(Reflow)라고 한다.
 
그리고 렌더 트리의 각 노드를 화면에 그려내야 하는데, 이 과정을 페인팅(Painting)이라고 한다. 모든 시각적인 요소를 화면에 그리는 과정이며, 브라우저는 이 작업을 최대한 빠르게 진행해야 한다. 이때 페인팅이 처음 일어나는 것을 First Meaningful Paint(FMP, 최초 의미 있는 페인트)라고 한다. FMP 이후에 사용자는 웹 페이지가 유용하다고 인식한다.
 
페인팅은 레이아웃 트리의 요소를 GPU 레이어로 분리하여 페인트 및 리페인트 성능을 향상할 수 있다. video, canvas 태그와 opacity, transform 등의 속성들이 위 조건에 해당된다. 이를 통해 성능을 향상할 수 있지만, 메모리 자원 관리가 어려워진다.

FMP 이후의 페인팅은 더 빠르게 수행되어야 하는데, 이때 합성(Compositing)이 일어난다. 합성을 통해 생성된 모든 레이어들을 일정한 순서에 맞게 합쳐지며 정확한 렌더링을 보장한다.



5. 상호작용 (Interactive)
렌더 과정이 끝나고 나면, 메인 스레드는 동적으로 다운로드한 Javascript 등을 실행하기 위해 일정 시간 동안 점유 된다. 따라서 메인 스레드가 점유되어 있을 동안에는 상호 작용이 불가능하다.

Time to Interactive(TTI)는 웹 페이지가 상호작용이 가능할 때까지 걸린 시간이다. 보통 First Contentful Paint(FCP, 최초 콘텐츠가 포함된 페인트) 이후에 사용자는 웹 페이지가 로드되었다고 느끼고, FCP 이후 상호작용까지 50ms 이내로 응답할 때 상호작용 가능하다고 여겨진다. 메인 스레드가 다른 작업에 점유되고 있다면 그만큼 상호작용 가능 시점이 늦춰진다. 따라서 최적화된 웹 페이지 로딩을 위해선 메인 스레드 점유를 줄이는 것이 좋다.


References
MDN Web Docs
velog - @adultlee