지난번에는 이 주제를 다룰 때에는 주소창에 url을 입력하고 화면에 웹 페이지를 사용자가 볼 수 있게 띄우는 일이 모두 포함되는 것으로 생각하고, 방대한 양에 헤맸었다.
결국
브라우저 렌더링
보다는 브라우저 렌더링을 위해 리소스를 어떻게 받아오는 지에 대해 공부해왔었다.오늘은 그 리소스를 받아와 어떻게 사용자가 볼 수 있는 화면으로 띄우는지 즉, HTML/CSS/JavaScript를 어떻게 렌더링 하는 지에 대해 알아보겠다.
렌더러 프로세스의 내부 작업
렌더러 프로세스가 준비되면 브라우저 프로세스에서 문서 리소스를 수신한다.
이를 통해 수행하는 렌더러 프로세스의 핵심 작업은 HTML, CSS, JavaScript 파일을 사용자가 상호 작용할 수 있는 웹 페이지로 변환하는 것이다.

렌더러 프로세스에서 하는 일은 이 외에도 다양하다. 자세한 내용이 궁금하다면 아래 자료에서 확인할 수 있다.
파싱
HTML 텍스트를 컴퓨터가 이해할 수 있는 형태로 파싱하는 과정이 필요하다.
1. DOM 트리 생성
HTML 표준에 따라 HTML 텍스트를 구문 분석하여 가장 먼저 하는 일은 DOM 트리를 생성하는 것이다.
DOM 트리는 어떤 과정으로 만들어지나요?

이 부분까지 자세히 설명된 자료들도 있다. 꼭 알아야 하는지는 모르겠으나 DOM이 생성되는 과정이 어떻게 되길래 React에서 DOM 트리에 접근하는 것을 지양하라고 하는지 궁금하다면 한 번 찾아보는 것도 좋을 것 같다. 지난 스터디 자료에 조금 설명돼있긴 하다.
HTML 태그를 잘못 작성해도 오류가 나지 않는 이유
이는 HTML 사양이 이러한 오류를 정상적으로 처리하도록 설계되었기 때문이다.
2. 하위 리소스 로드
HTML 파일에서 사용하는 이미지, CSS, JavaScript를 로드한다.
이는 DOM 트리를 만들며 만나는 순서대로 하나씩 요청을 할 수도 있겠지만, 속도를 높이기 위해
preload scanner
가 실행된다.DOM 트리가 만들어지는 과정 중에 토큰을 생성하는 과정이 있는데 그 때 <img>, <link> 같은 것이 있으면 프리로드 스캐너가 브라우저 프로세스의 네트워크 스레드에 요청을 보낸다.

JavaScript 실행을 위해서는 HTML 문서의 파싱이 일시 중지 될 수 있다.
JavaScript 코드로 인해 전체 DOM 구조에 영향을 줄 수 있기 때문이다.
이 과정을 최적화 하기 위해 defer, async, 모듈 등을 사용할 수 있다.
또한
<link rel="preload">
를 통해 리소스가 DOM 트리를 그리는 데에 필요하고 가능한 한 빨리 다운로드 하고 싶다는 것을 브라우저에 알릴 수 있다.3. CSSOM 트리 생성
파싱 과정에서 CSS 파일을 로드하게 되면 CSSOM 트리를 생성하게 된다.

CSS 파일이 정의되어 있거나 html 태그에 정의한 style 요소가 없는 즉, 스타일이 따로 지정되지 않은 엘리먼트는 브라우저 상에서 기본적으로 가지고 있는 스타일로 CSSOM 트리를 구축한다. (이 때문에 reset css를 정의하는 것이기도 함.)
DOM 트리 생성과 CSSOM 트리 생성의 타임라인이 정확히 어떻게 이루어지는지 모르겠다. 기본적으로는 병렬인 것 같으며 CSS가 외부 링크로 정의된 경우 렌더링이 블로킹 된다고 한다.
4. Render Tree 생성
DOM Tree와 CSSOM 트리를 합쳐서 Render Tree를 만든다.
Render Tree는 화면에 표시되어야 할 모든 노드의 컨텐츠, 스타일 정보를 포함하고 있는 트리다.

Render Tree가 만들어지는 과정을 간략하게 말하자면 다음과 같다.
document 객체부터 각 노드를 순회하면서 각각에 맞는 CSSOM을 찾아 렌더와 관련된 요소들을 렌더 트리에 포함시키게 된다.
이 때, meta 태그나 display: none 속성을 가진 요소들은 렌더와 관계가 없기 때문에 렌더 트리에 포함되지 않는다.
CSS로 화면에 보일지/숨길지 여부를 조절할 수 있는 속성인 visibility vs display vs opacity
오직 display: none만이 Render Tree에서 제외된다.
5. Layout
브라우저 렌더링 엔진은 CSS 2.1 스펙을 이용하여 브라우저 내 CSS의 표준에 맞춰 제작되었다.
그렇기에 브라우저의 레이아웃은 모든 것이 박스로 구성된다.
이러한 박스의 크기와 위치를 계산하는 과정이 바로 Layout이며 이 과정에서 아래 그림과 같은 Layout 트리를 만들게 된다.

전체(Global) vs 부분(Incremental) 레이아웃
최적화를 더 알아보면 좋은 부분 같다.
6. 여러 Layer로 분리하기

이 부분은 시간이 부족하여 잘 정리된 블로그 글을 그대로 가져왔음.
포토샵이나 Figma 같은 편집 툴을 사용해보셨다면 Layer 라는 개념에 익숙하실 겁니다.
브라우저의 레이어도 흡사합니다. 렌더링 될 요소들을 층 형태로 나누어 둔 것을 의미합니다.
그리고 Update Layer Tree는 렌더링이 될 최종 레이어들을 계산하여 생성하는 과정입니다. 이 과정에서도 Layer Tree를 생성합니다.
TMI) 브라우저의 내부 자료 구조를 사람들이 Forest🌳 라고 부르곤 하는데 이렇게 다양한 트리가 생성되기 때문입니다….ㅎ

Layer가 생성되는 조건은 위와 같습니다.8번을 자세히 보시면 브라우저는 생성 조건 외에도 자체적으로 레이어를 생성하기도 합니다.
실제로 레이어를 분리하면 이런 식으로 레이어 별로 렌더링 됩니다.
여기서부터 직접 추가한 내용
개발자도구의 Performance 탭에서는 이 과정이 Update Layer Tree 라고 표시됨
모든 요소에 레이어를 제공하고 싶을 수 있지만 과도한 수의 레이어를 만들어 합성(이후 과정)을 하면 매 프레임마다 페이지의 작은 부분을 래스터화 하는 것보다 작업 속도가 느려질 수 있다. 이에 대한 자세한 내용은
7. Paint
이 부분은 시간이 부족하여 잘 정리된 블로그 글을 그대로 가져왔음.

브라우저의 페인트 과정은 프린트하는 것과 비슷합니다.
한 번에 확 렌더링되는 것이 아니라 프린터처럼 천천히 한 픽셀씩 그립니다.즉, 페인트를하기 위해선 Render Tree를 하나씩 그려야 합니다.

출처: https://developer.chrome.com/blog/inside-browser-part3/
이 과정에선 위 과정들과는 다르게 Tree가 아니라 Records, 즉 순서에 대한 메모를 생성하게 됩니다.
여기서부터 직접 추가한 내용
Paint 과정에서 만드는 records는 레이아웃 트리를 기반으로 만들어진다.
그렇기에 레이아웃 트리에서 변경 사항이 있는 경우 Paint 과정 또한 다시 실행된다.
이를 알고 있으면 최적화를 하는 데에 도움이 된다.
8. Composite
이제 브라우저는 문서의 구조, 각 요소의 스타일, 페이지의 기하학 및 페인트 순서를 알고 있으므로 페이지를 그릴 수 있다.
이 정보를 화면의 픽셀로 변환하는 것을 래스터화라고 한다.
그런데 최신 브라우저는 단순히 래스터화 하는 것을 넘어 합성이라는 더욱 정교한 프로세스를 가진다.
합성은 페이지의 일부를 레이어로 분리하고 개별적으로 래스터화 한 다음 컴포지터 스레드라는 별도의 스레드에서 페이지로 합성하는 기술이다.
스크롤이 발생하면 레이어가 이미 래스터화 되어 있으므로 새 프레임을 합성하기만 하면 된다.
애니메이션은 레이어를 이동하고 새 프레임을 합성하면 된다.
레이어 트리가 생성되고 페인트 순서가 결정되면 메인 스레드는 해당 정보를 컴포지터 스레드에 커밋한다.
그런 다음 컴포지터 스레드가 각 레이어를 래스터화 한다.
레이어는 페이지의 전체 길이만큼 클 수도 있으므로 컴포지터 스레드는 레이어를 각 타일로 나누어 래스터 스레드로 보낸다.
래스터 스래드는 각 타일을 래스터화 하여 GPU 메모리에 저장한다.

정확히 어떤 경우에 타일링을 하고 하지 않는 걸까? 무조건 하는 것일까? 래스터 스레드를 거치지 않고도 래스터화를 하는 것이 맞을까?
그외 합성 과정 더 자세한 내용
면접 질문에 답변하기
이는 질문을 세 가지 형태로 분류해보겠다.
- 주소창에 naver.com을 입력한 이후 그 페이지를 얻어올 때까지의 과정을 설명해주세요.
- 브라우저의 렌더링 과정에 대해 설명해주세요.
- 브라우저 리소스를 받아오는 과정 + 렌더링 과정을 설명해주세요. (1 + 2)
일단은 직접 정리하기엔 시간이 부족할 것 같아서 각각의 분류에 맞는 이미 정리된 답변들을 가져와보겠다.
1) 주소창에 naver.com을 입력한 이후 그 페이지를 얻어올 때까지의 과정을 설명해주세요.
출처 - https://www.nokiahub.site/dev/browser/ 브라우저가 주소창에 입력된 URL 값을 DNS 서버로 전송하여 IP주소를 받아옵니다. 해당 IP 주소로 html과 같은 리소스 파일을 요청합니다. 받아온 리소스 파일을 브라우저가 렌더링하여 사용자에게 보여줍니다.
2) 브라우저의 렌더링 과정에 대해 설명해주세요.
- 사용자가 특정 페이지에 접속하여 HTML을 서버로부터 내려받으면, 브라우저의 렌더링 엔진에서는 이를 파싱한다.
- HTML 파싱을 진행하면서, DOM 트리를 만들게 되는데, 이 때 Link 태그를 만나 StyleSheet를 내려받게 될 경우 CSS 파싱을 통해 CSSOM 트리를 만들게 된다.
- 이 일련된 과정을 통해 둘을 결합하여 렌더 트리를 만들고, 레이아웃 작업을 통해 사용자에게 그려줄 영역을 계산한 뒤, 화면에 뿌려주게된다.
- 위 과정을 진행하면서 자바스크립트를 만나면, 자바스크립트 런타임 환경에 컨트롤(수행권한)을 넘겨 결과 값을 받는다.이 과정 중, DOM파싱은 중단된다.
- 생성된 DOM 노드의 레이아웃 수치(너비, 높이, 위치 등) 변경 시 영향 받은 모든 노드의 수치를 재계산하여, 렌더 트리를 재생성하는 과정을 Reflow 과정이라고하며, 이 과정이 끝난 후 재생성된 렌더 트리를 다시 그리게 되는데 이 과정을 Repaint라고 합니다.
브라우저가 html 파일을 파싱하여 DOM 트리를 구성합니다. css 파일 또한 파싱하여 CSSOM 트리를 구성하고, 이 두 트리를 합쳐 렌더 트리를 구성합니다. 이 렌더 트리를 기반으로 렌더링하게 됩니다.
- HTML 마크업을 Parsing(처리)하여 DOM 트리를 빌드한다. (“무엇을” 그릴지 결정한다.) (DOM 파싱)
- CSS Parsing(처리)하여 CSSOM 트리를 빌드한다. (“어떻게” 그릴지 결정한다.) (CSS 파싱)
- DOM 및 CSSOM 을 결합하여 렌더링 트리를 형성한다. (“화면에 그려질 것만” 결정) (Combination)
- 렌더링 트리에서 레이아웃을 실행하여 각 노드의 기하학적 형태를 계산한다. (“Box-Model” 을 생성한다.) (Layout)
- 개별 노드를 화면에 페인트한다.(or 래스터화) (Painting)
- 렌더링이 완료된 상태에서 사용자의 인터랙션에 의해 화면의 일부 영역이 변경된다면,
리플로우
또는리페인트
가 발생한다.
3) 브라우저 리소스를 받아오는 과정 + 렌더링 과정을 설명해주세요.
- 주소창에 입력된 주소를 통해 브라우저 URL을 해석해 서버를 찾아간다.
- 이후 DNS가 연결해 줄 곳을 찾는다 (실제서버)
- 서버에서 클라이언트가 요청한 자원을 보내준다. (보통 HTML 문서)
- 클라이언트는 HTML문서를 파싱하여 DOM을 생성한다.4-1. 중간에 CSS나 JS 스크립트를 다운받는 태그를 만나면 DOM 생성을 중지하고 해당 자원들을 다운로드 한다.
- HTML -> DOM, CSS -> CSSOM 을 생성한다.
- 만들어진 DOM과 CSSOM을 브라우저에 렌더링 하기 위해 렌더 트리로 결합한다.
- 만약 script 태그를 만나면, css와 동일하게 JS코드를 실행하기 위해 파싱을 중단하고, 이후 JS엔진을 실행하고 JS코드를 파싱한다.