다시 해야겠다 ..
주제 선정 이유
SSR과 Next.js 실행 원리를 잘 이해하고 싶은데 브라우저 렌더링이 배경 지식인 것 같아서
⇒ 알고보니 내가 정말 궁금했던 건 렌더링보다는 렌더링을 하기 전에 HTML을 어떻게 받아오는지와 같은 통신 쪽이었다 (주소창에 주소 치면 어떤 일이 일어나는가?의 초반부) 그래도 이 부분도 결국 그 과정에 연결되어 있기도 하고, 프론트엔드 개발자로서 꼭 알아야 하는 내용이니 준비해보았다.
목표
- 브라우저 렌더링의 대략적인 흐름에 대해 이해하기
- 모든 부분에 있어 딥하게 들어가려면 끝도 없으니 필요하거나 궁금한 부분은 추후에 따로 알아보려고 한다. 어설프게 딥한 부분을 언급했다가 오히려 헷갈리고 쓸데 없이 궁금증만 너무 많이 유발해서 삭제한 부분이 많다.
- 렌더링 과정에서 자바스크립트는 어떻게 파싱되고 실행되는지에 대한 내용이 빠졌다. 이 부분은 꼭 추후에 공부해보자
- 브라우저 렌더링의 흐름을 이해함으로써 실제로 프론트엔드 개발을 할 때 어떤 효용을 얻을 수 있는지 알아보기
웹 브라우저의 구조
웹 브라우저의 공통적인 구조는 다음과 같다.
1. User Interface
주소창, 이전/다음/새로고침 버튼 등 웹 페이지를 제외하고 사용자와 상호작용하는 인터페이스
사용자가 요청한 페이지를 제외한 모든 부분을 지칭한다.
2. Rendering Engine
요청 받은 내용을 브라우저에 나타내는 역할
(참고) 렌더링 엔진과 레이아웃 엔진
이 둘은 이론상으로 나뉜다고 볼 수도 있으나, 실제론 밀접하게 연관되어 있기 때문에 하나로 간주하는 경우가 많다고 한다.
3. Browser Engine
유저 인터페이스와 렌더링 엔진 사이에서 동작을 제어하는 브라우저 엔진
4. Networking
각종 네트워크 요청을 수행하는 역할
5. UI Backend
체크박스나 버튼과 같은 기본적인 위젯을 그려주는 역할
6. Data Persistence
localStorage나 Cookie와 같이 보조 기억 장치에 데이터를 저장하는 파트
7. Javascript Interpreter
자바스크립트 코드를 실행하는 인터프리터
렌더링 엔진
브라우저 렌더링 과정에서 중요한 것은 렌더링 엔진이다.
렌더링 엔진은 웹 브라우저마다 조금씩 다르다.
참고로 크롬은 대부분의 브라우저와 달리 각 탭마다 별도의 렌더링 엔진 인스턴스를 유지한다.
렌더링 엔진은 HTML 및 XML 문서와 이미지를 표시할 수 있다.
물론 플러그인이나 브라우저 확장 기능을 이용해 PDF와 같은 다른 유형도 표시할 수 있다.
그러나 우리가 개발하는 HTML/CSS, 이미지 등을 표시하는 주된 사용 패턴에 초점을 맞춰 설명하겠다.
렌더링 엔진의 동작 과정
이 과정을 Critical Rendering Path라고 한다.
1) DOM Tree와 CSSOM Tree의 생성
HTML 코드는 어휘 분석을 통해 HTML5 표준에 지정된 고유한 토큰으로 변환된다.
- StartTag [tag] - 특정 tag가 열렸다는 의미를 가짐.
- EndTag [tag] - 특정 tag가 닫혔다는 의미를 가짐.
이후 브라우저의 렉싱 과정을 통해 토큰이 해당 속성과 규칙을 정의하는 노드 객체로 변환된다.
그리고 각 노드가 서로 연관성을 가질 수 있도록 트리를 생성하며 이것이 바로 DOM 트리이다.
HTML 문서의 모든 것들은 DOM을 구성하게 된다. (element, attribute, text, comment 등)
CSS로는 CSSOM Tree가 만들어짐.
CSS 파일이 정의되어 있거나 html 태그에 정의한 style 요소가 없는 즉, 스타일이 따로 지정되지 않은 엘리먼트는 브라우저 상에서 기본적으로 가지고 있는 스타일로 CSSOM 트리를 구축한다.

2) Render Tree 생성
DOM Tree와 CSSOM 트리를 합쳐서 Render Tree를 만든다.
Render Tree는 화면에 표시되어야 할 모든 노드의 컨텐츠, 스타일 정보를 포함하고 있는 트리다.

Render Tree가 만들어지는 과정을 간략하게 말하자면 다음과 같다.
document 객체부터 각 노드를 순회하면서 각각에 맞는 CSSOM을 찾아 렌더와 관련된 요소들을 렌더 트리에 포함시키게 된다.
이 때, meta 태그나 display: none 속성을 가진 요소들은 렌더와 관계가 없기 때문에 렌더 트리에 포함되지 않는다.
(참고) visibility vs display vs opacity
오직 display: none만이 Render Tree에서 제외된다.
3) Render Tree 배치
Render Tree가 생성된 후에는 Layout이라는 과정을 거친다.

이는 뷰포트 내에서 페이지에 출력될 노드들의 크기와 위치, 레이어 간의 순서 정보를 계산하는 과정이다.
이때 CSS에서 %나 em 같은 상대적인 단위를 사용했을 때는 뷰포트에 맞춰 픽셀 단위로 변환된다.
(참고) 레이어란?
z축을 활용하는 3차원 개념(쌓임 맥락)을 렌더링 과정에 삽입하기 위해 필요한 개념.
그 후 마지막으로 이를 화면에 실제 픽셀로 그려지도록 변환하는 Paint 과정을 거친다.
이 과정에서 렌더 트리에 포함된 요소들이나 텍스트, 이미지들이 실제 픽셀로 그려진다.
UI가 업데이트 되는 3가지 상황
1. 다시 Layout이 발생하는 경우

보통 요소의 크기나 위치가 바뀔 때, 혹은 브라우저 창의 크기가 바뀌었을 때 위 그림의 순서에 따라서 다시 발생한다.
이 때 레이아웃 수치를 다시 계산해서 배치를 해야 하기 때문에 레이아웃 과정이 다시 발생한다.
이에 맞춰서 다시 Paint도 하고 레이어 합성도 해야 한다.
- layout이 발생한다는 게 무슨 말?
⇒ 발생하는 게 아니라 발생되는 거 아닐까
- 그림에서 Layout 앞의 과정이 잘 이해 안 간다 요소의 크기나 위치가 바뀌는 건 보통 JavaScript를 통해서 발생하는 것일텐데 창의 크기가 바뀌는 건 JavaScript가 필요 없지 않나? 앞에껀 왜 있는거야? 설명도 안 하고 헷갈린다
- 요소의 크기나 위치가 바뀔 때가 아니라 바뀌어야 할 때 아닌가? 레이아웃이 발생 해야 바뀌는 거 아닌가?
2. Paint부터 다시 발생되는 경우

배경 이미지나 텍스트 색상, 그림자 등 레이아웃의 수치를 변화시키지 않는 스타일의 변경이 일어났을 때 발생한다.
3. 레이어의 합성만 다시 발생하는 경우

레이어는 포토샵과 비슷하게 페인팅 할 영역을 나누어 놓는 것을 의미한다.
크롬의 경우에는 레이아웃 과정 이후에 정해진 기준이나 필요에 의해서 브라우저가 레이어를 생성한다.
그리고 렌더 트리에 있는 노드 객체들은 생성된 레이어에 포함되게 된다.
레이어들은 트리 형태로 구성이 된다.
렌더링 엔진이 각 레이어를 프린팅 과정에서 각각 그려준 다음 하나의 비트맵으로 합성해서 페이지를 완성한다.
이 경우에는 레이아웃과 페인트 과정도 수행하지 않고 레이어의 합성만 발생하기 때문에 성능상으로 가장 큰 이점을 가진다.
설명 너무 추상적이라 진짜 모르겠음
- 프린팅 과정?
- 레이어는 어디에 속하는데?
- 모든 노드는 레이어에 속하나?
CSS 트리거
애니메이션 렌더링 최적화에 활용할 수 있음.

left X transform O
브라우저의 렌더링 과정
1. 통신
사용자가 주소창에 주소를 입력하면 UI 스레드는 입력되는 내용이 검색어인지 url인지 확인하고 입력된 내용을 파싱해서 검색 결과로 이동할지 요청한 사이트로 이동할지 결정한다.
사용자가 enter를 누르면 UI 스레드가 네트워크 호출을 시작한다.
그러면 네트워크 스레드가 요청을 처리하고 응답이 HTML 파일이라면 응답 결과를 렌더러 프로세스에 전달한다.
2. DOM 트리 구축
HTML 데이터를 수신하기 시작하면 렌더러 프로세스의 메인 스레드는 HTML을 파싱해서 DOM 트리로 반환한다.
3. CSSOM 트리 구축
CSS 파일이 정의되어 있거나 html 태그에 정의한 style 요소가 없는 즉, 스타일이 따로 지정되지 않은 엘리먼트는 브라우저 상에서 기본적으로 가지고 있는 스타일로 모든 정보들을 합쳐서 CSSOM 트리를 구축한다.
4. Render 트리 생성
최종적으로 화면에 표시되는 모든 노드와 노드의 스타일 정보를 포함한다.
5. Layout (reflow)
이 과정은 HTML 문서의 최상위에서 실행하고 재귀적으로 실행된다 (왜)
레이아웃 과정에서 노드들이 많아지면 속도는 당연히 느려질 수밖에 없다.
따라서 브라우저는 자체적으로 최적화 로직을 탑재하고 있다
그 중 하나가 더티 비트 시스템이다
특정 엘리먼트가 변경이나 추가 때문에 다시 배치가 필요하다면 해당 엘리먼트를 더티라고 표시한다.
그러면 레이아웃이 재귀적으로 실행될 때 더티 엘리먼트 부분만 다시 계산하여 리소스의 낭비를 줄일 수 있다.
이 계산은 즉시 수행되는 것이 아니라 비동기로 일괄 작업하기에 연산 횟수를 줄일 수 있다.
복잡한 변경이나 많은 추가가 있는 경우 브라우저 최적화만으로 충분하지 않기 때문에 이런 연산을 최소화 해야 한다.
6. Paint
레이아웃 단계를 통해 배치된 엘리먼트들에게 색을 입히고 레이어의 위치를 결정한다.
이 단계 역시 HTML 문서의 최상위 요소부터 재귀적으로 실행된다.
페인팅 순서는 가장 아래의 레이어 z-index가 낮은 순서대로 먼저 페인팅 된다.
Reflow, Repaint
reflow- layout + paint
repaint - paint

쌓임 맥락에 따라 다르다.
브라우저의 주요 기능
브라우저의 기능은 선택한 웹
리소스
를 서버에서 요청하여 브라우저 창에 표시하는 것 이다.리소스
는 보통 HTML문서 이지만, PDF, 이미지 등 일수도 있다. 이러한 리소스 위치는 사용자가 URI(Uniform Resource Identifier)
를 사용하여 지정한다.참고 자료
어느 글을 봐도 결국 흐름은 똑같고 또 세부 정보는 똑같이 모두 조금씩 다른 부분이 있어서 공통된 흐름만 가져오고 세부 정보는 한 가지 주제를 딱 정해서(ex 렌더 트리가 만들어지는 구체적인 과정, 더티 비트 시스템) 스스로 딥하게 파보는 것이 좋다고 생각해서 자료들을 다양하게 가져오려다 말았다.
면접 질문 예시
- naver.com을 입력한 이후 그 페이지를 얻어올 때까지의 과정을 설명하라
- 브라우저 리소스 받아오는 과정 + 렌더링 과정에 대해 설명하라
서론
브라우저에 url을 입력했을 때 웹 페이지가 그려지는 과정은 두 가지 단계로 나누어 볼 수 있다.
- 우리가 브라우저에 url을 입력했을 때, 웹 페이지를 그리기 위한 리소스(html, css, js, font 등)를 받아오는 과정
- 가져온 리소스를 통해 렌더링을 하는 과정
이 두 가지를 모두 설명하기엔 내용이 많아서 1번에 대해서만 자세히 설명해보겠다.
브라우저 아키텍처
먼저 브라우저가 실행되는 환경을 이해하기 위해 크롬 브라우저 아키텍처에 대해 알아보겠다.
브라우저 또한 하나의 응용 프로그램이며 이는 프로세스와 스레드로 실행된다.
이는 여러 스레드가 있는 하나의 프로세스이거나 IPC를 통해 통신하는 몇 개의 스레드가 있는 여러 프로세스일 수 있다.

참고로 웹 브라우저를 구축하는 방법에 대한 표준 사양은 없다.
한 브라우저의 접근 방식은 다른 브라우저와 완전히 다를 수 있다.
크롬 브라우저 아키텍처
그렇기 때문에 우리는 크롬 브라우저를 기준으로 브라우저 아키텍처를 알아보도록 하겠다.

크롬 브라우저 아키텍처는 위 그림으로 나타낼 수 있다.
렌더러 프로세스, 플러그인 프로세스가 여러 개인 것이 특징적이다. (그래서 크롬이 유독 무겁구나!)
각각의 프로세스는 무슨 일을 하는가?

1) Brower Process
브라우저의 User Interface를 제어한다.
UI 스레드와 네트워크 스레드를 가지고 있다.
사용자 입력이 일어나면 UI 스레드가 그것을 처리한다.
이때 외부에 요청을 보내야 하면(ex 주소창에 url 입력) 네트워크 스레드가 요청을 보낸다.
2) Renderer Process
브라우저의 화면을 그리는 일을 담당한다.
따라서 탭 하나 당 하나가 생성된다.
3) Plugin Process
플러그인이 한 화면 안에 여러 개 있을 수 있기 때문에 여러 개다.
각 플러그인 당 하나씩 생성된다.
4) GPU Process
브라우저 프로세스와 렌더러 프로세스가 담당하는 모든 화면을 그리는 역할을 한다.
크롬 브라우저 아키텍처의 장점

- 응답 없음 상태 대응
만약 한 탭에서 에러로 인해 응답이 없는 상태가 되었다면 해당 프로세스를 강제 종료 시켜야 한다.
그런데 그렇다고 해도 다른 탭은 종료시키지 않아도 된다.
(IE 쓸 때에는 다 종료시켜서 불편했던 기억 ..)
- 보안
프로세스는 각자의 고유한 메모리 영역을 가지고 있기 때문에 프로세스 간 접근이 쉽지 않아 보안에 이점이 있다.
이 때문에 더 나아가 iframe별로도 서로 다른 프로세스를 가지도록 진화했다.
따라서 크롬 브라우저는 same-origin policy를 지켜 각 origin 별로 각자의 데이터를 고유의 프로세스가 관리한다.
그래서 외부에서 권한 없이 데이터에 접근할 수 없다.

크롬 브라우저 아키텍처의 단점
렌더러 프로세스가 계속 늘어날 수 있기 때문에 필요한 메모리 영역도 계속 늘어난다.
따라서 브라우저 실행환경에서의 CPU와 메모리가 충분하지 않다면 메모리를 절약하기 위해 프로세스들을 통합하는 작업을 한다.
크롬 브라우저는 실행되는 환경에서의 CPU와 메모리의 한계치를 알고 있으며, 이 한계치에 도달하게 되면 프로세스를 통합하여 메모리를 절약한다.
(내용 추가)
브라우저에 url을 입력했을 때, 웹 페이지를 그리기 위한 리소스를 받아오는 과정
1. Handling inputs: 사용자가 url 창에 text를 입력하면

사용자가 url 창에 text를 입력하면 브라우저 프로세스에 있는 UI 스레드가 유저가 입력한 text 값을 분석한다.
이에 따라 text 값을 구글 검색 엔진에 넘겨주어 검색이 되도록 할지, 요청한 사이트로 이동하게 할지 여부를 결정한다.
2. Start navigation: 사용자가 Enter 키를 누르면

사용자가 Enter 키를 누르면 먼저 UI 스레드가 네트워크 호출을 시작하여 사이트 콘텐츠를 가져온다.
이때 UI 스레드는 로딩 스피너를 작동시킨다.
또한 네트워크 스레드는 DNS 조회 및 요청에 대한 TLS 연결 설정과 같은 적절한 프로토콜을 거친다.
이후 네트워크 스레드에 HTTP 301 response가 오면 UI 스레드에게 리다이렉트 해야 함을 전달한다.
3. Read response: response body가 네트워크 스레드로 들어올 때
컨텐트 타입을 확인하고 안정성을 검증한다.
1) Content-Type 확인
응답 본문(페이로드)이 들어오기 시작하면 네트워크 스레드는 필요한 경우 스트림의 처음 몇 바이트를 확인한다.
응답의 Content-Type 헤더가 누락되거나 잘못됐을 수 있으므로 MIME 스니핑이 여기에서 수행된다.
MIME 스니핑?
Content sniffing, also known as media type sniffing or MIME sniffing, is the practice of inspecting the content of a byte stream to attempt to deduce the file format of the data within it.

응답이 HTML 파일인 경우 다음 단계는 렌더러 프로세스에 데이터를 전달하는 것이지만 zip 파일이나 다른 파일인 경우 다운로드 요청이므로 데이터를 다운로드 관리자로 전달해야 한다.
2) 세이프 브라우징
세이프 브라우징 확인을 통해 도메인과 응답 데이터가 알려진 악성 사이트와 일치하는 것으로 보이면 네트워크 스레드가 경고 페이지를 표시하도록 한다.

3) CORB 검사
민감한 사이트 간 데이터가 렌더러 프로세스에 전달되지 않도록 하기 위해 CORB(Cross Origin Read Blocking) 검사가 수행된다.
4. Find Renderer Process: 3번 과정이 끝난 후, 요청한 사이트로 이동해야 하면
모든 검사가 완료되고 네트워크 스레드가 브라우저가 요청된 사이트로 이동해야 한다고 확신하면 네트워크 스레드는 데이터가 준비되었음을 UI 스레드에 알린다.
그런 다음 UI 스레드는 웹 페이지 렌더링을 수행할 렌더러 프로세스를 찾는다.

네트워크 요청이 응답을 받는 데 수백 밀리초가 걸릴 수 있으므로 이 프로세스의 속도를 높이기 위한 최적화가 적용된다.
UI 스레드가 2단계에서 UI 스레드는 네트워크 요청과 병렬로 렌더러 프로세스를 사전에 찾거나 시작하려고 시도한다.
이 과정이 예상대로 진행되면 렌더러 프로세스는 네트워크 스레드가 데이터를 수신했을 때 이미 대기 위치에 있다.
탐색이 교차 사이트로 리디렉션되는 경우 이 대기 프로세스가 사용되지 않을 수 있으며, 이 경우 다른 프로세스가 필요할 수 있다.
5. Commit Navigation: data, 렌더러 프로세스가 준비되면
이제 데이터와 렌더러 프로세스가 준비되었으므로 commit navigation을 위해 브라우저 프로세스(UI 스레드)에서 렌더러 프로세스로 IPC가 전송된다. 이 과정이 렌더링 직전의 단계이다.
또한 렌더러 프로세스가 HTML 데이터를 계속 수신할 수 있도록 데이터 스트림을 전달한다.
브라우저 프로세스가 렌더러 프로세스에서 커밋이 발생했다는 확인을 받으면 네비게이션이 완료되고 문서 로드 단계(렌더링 과정)가 시작된다.
그 전에 주소 표시줄이 업데이트되고 보안 표시 및 사이트 설정 UI에 새 페이지의 사이트 정보가 반영된다.
탭의 세션 기록이 업데이트(=세션 히스토리가 새롭게 추가)되어 뒤로/앞으로 버튼이 방금 탐색한 사이트를 통해 이동한다.
탭이나 창을 닫을 때 탭/세션 복원을 용이하게 하기 위해 세션 기록이 디스크에 저장된다.

추가) 렌더링이 완료되면
네비게이션이 커밋되면 렌더러 프로세스는 리소스 로드를 계속하고 페이지를 렌더링한다.
렌더러 프로세스가 렌더링을 완료하면 IPC를 다시 브라우저 프로세스로 보낸다.(이는 페이지의 모든 프레임에서 모든
onload
이벤트가 발생하고 실행이 완료된 후임).이 시점에서 UI 스레드는 탭에서 로딩 스피너를 중지한다.
궁금증..
- onload 이벤트가 정확히 언제 발생하고 언제 끝나는지