
critical rendering path 이라고도 하며, 프론트엔드 면접때 꼭 나오는 단골질문이랍니다..🙃
파싱
프로그래밍 언어의 문법에 맞게 작성된 텍스트문서를 어휘분석하여 문자열 토큰으로 분해한 뒤 이 토큰에 문법적 의미와 구조를 반영하여 파스 트리를 생성하는 일련의 과정!
파싱이 종료된 후에는 파스트리를 기반으로 중간 언어(바이트코드)를 생성하고 실행한다~
렌더링
HTML, CSS, JS로 작성된 문서를 파싱하여 브라우저에 시각적으로 출력하는 것
커넥션당 하나의 요청과 응답만 처리한다!
리소스 동시 전송이 불가능하여 요청하는 리소스 개수에 비례하게 응답시간이 증가한다.
커넥션당 다중 요청과 응답이 가능하다!
자세한 내용은 구글의 HTTP/2소개를 읽어 봅시다...
브라우저 렌더링 다 정리하고 한번 봅시다.
순수텍스트인 HTML을 시각적인 픽셀로 렌더링하려면, HTML문서를 브라우저가 이해할 수 있는 자료구조(객체)로 변환하여 메모리에 저장해야 한다!

🤔 토큰과 노드는 무슨 차이에요?
토큰은 단순히 문법적 의미를 갖는 코드최소단위이고,
노드가 되어서야 비로소 객체로 생성된다!
HTML을 한 줄씩 파싱하다 CSS 로드 태그(link, style)을 만나면, DOM 생성을 일시 중단하고 해당 CSS파일을 서버에 요청하여 파싱해다 CSSOM을 만든 뒤 다시 DOM 생성을 재개한다!

DOM과 CSSOM을 결합-!!!

단순 문자열인 js 소스코드를 어휘분석하여 토큰으로 분해하는 과정.
렉싱이라고 부르기도 하는데 토크나이징과 미묘한 차이가 있다..
😧 그 미묘한 차이를 설명을 해달라고요.. 안 해줘서 찾아봄.
- 토크나이징: 일반적으로 공백(탭, 공백, 새 줄)을 찾아 텍스트 스트림을 토큰으로 나눈다!
- 렉싱: 기본적으로 토크나이저! 여기에 추가 컨텍스트가 첨부된다.
👉 그러니까 대충 토크나이징이 더 큰 의미라고.
토큰들의 집합을 구문분석하여 AST(추상구문트리)를 생성한다.
😏 TypeScript나 Babel, Prettier도 AST를 사용한 거랍니다.
따라서 위 라이브러리들도 일종의 파서라고 할 수 있다네요!
AST는 바이트코드로 변환되어 인터프리터에 의해 실행된다!
🤭 참고로 V8엔진은요
터보팬이라고 불리는 컴파일러가 자주 쓰는 코드를 최적화된 머신 코드로 만들어 성능을 최적화하는 기능이 있다고 하네요!
코드 사용 빈도가 적어지면 알아서 이 최적화를 해제시킨다고 합니다.
🚚 참고로 터보팬은요
메인스레드를 감시하다가 일정 기준 이상 동일한 함수가 호출되면 히든클래스와 인라인 캐싱을 이용해 최적화를 진행한다고 하네요.
HTML을 한 줄씩 파싱하다 JS태그(script) 을 만나면, DOM 생성을 일시 중단하고 해당 JS을 서버에 요청하여 JS를 파싱한다!
HTML은 위에서 아래로 한 줄씩 읽어내려가며 순차적으로 파싱을 진행하기 때문에,
HTML 레이아웃이 완성되지 않은 상태에서 JS로 DOM에 접근하면 문제가 발생할 수 있다!
👉 따라서 scrip태그를 HTML 후반부에 놓는 것을 권장한다!
위 문제를 해결하기 위해 HTML5부터 추가된 어트리뷰트로,
HTML파싱과 외부 JS파일 로드가 비동기적으로 동시진행된다.
👉 단, src 어트리뷰트를 통해 외부 js파일을 로드하는 경우에만 사용이 가능하다
<script async src="extern.js"/> //순서 보장x
<script defer src="extern.js"/>


일련의 렌더링 과정을 담당하는 브라우저의 프로세스!
각각의 과정은 해당 프로세스 내부 스레드들이 하나씩 맡아 담당한다!
가진 것: HTML 텍스트 코드
HTML을 파싱하여 DOM 트리를 만든다!
가진 것: Dom 트리
CSS를 계산해 Computed Style을 도출한다!
모든 수치(% 등..)를 px단위로 변환한다!
가진 것: Dom 트리(색칠됨)
DOM 트리의 각 요소들이 배치될 좌표를 계산하여 Layout 트리를 만든다!
🌳 속성 트리(property tree)
레이아웃 트리를 순회하면서 clip, transform, opacity등의 속성 정보만 뽑아낸 트리!
기존에는 이런 정보를 분리하지 않고 노드가 가지고 있어서, 특정 노드 속성이 변경되면 해당 노드의 하위 노드에도 이 값을 다시 반영하면서 노드를 순회해야 했지만....
최신 Chrome에서는 이런 속성만 별도로 관리하고 각 노드에서는 속성 트리의 노드를 참조하는 방식으로 변경되고 있다~
가진 것: Dom 트리(색칠됨), Layout 트리
css에서 z-index나 position 등 레이어 관련 정보를 추출하여 Layer 트리를 만든다!
레이어가 많을수록 합성 비용과 메모리 소비가 많아진다!
😏 개발자 모드에서 레이어 확인하기
개발자모드의 more tools에서 Layer를 입체적으로 확인할 수 있다!
💥 layer explosion(레이어 과도 현상)
크롬에는 이를 막기 위해 특정 경우 레이어를 생성하지 않거나 합치는 기능이 있다!
가진 것: Dom 트리(색칠됨), Layout 트리, Layer 트리
Layout 트리와 Layer 트리로 페인트 레코드를 만든다!
이 과정은 메인스레드가 아니라 컴포지터 스레드가 담당합니다!
페인트 레코드로 타일(컴포넌트)로 만든다!
이렇게 조각난 타일들을 필요한 부분만 우선적으로 렌더링할 수 있다!
이 과정은 래스터 스레드가 담당합니다!
화면을 픽셀로 변환하는 작업. 시간을 매우 소모한다!
위에서 만든 타일로 실제 화면에 보여질 비트맵을 만든다~~
이 타일은 해상도 별로 여러 세트를 만들어 줌인, 줌아웃에 따라 해상도를 바꿀 수 있게 해준다고.
😌 각각의 타일은 말이죠
각각의 래스터 스레드에서 래스터화가 진행됩니다
다 만들면 GPU 메모리에 비트맵을 저장하고 컴포지터 스레드로 넘겨줘요
이 과정은 컴포지터 스레드가 담당합니다
🔖 Draw Quad
타일이 래스터화된 후의 정보 모음(타일이 그려질 위치 등..)
컴포지터 스레드는 이 드로 쿼드들을 모아 합성프레임(compositor frame)을 만든다~
컴포지터 스레드는..
래스터 스레드간 우선순위를 지정할 수 있다!
👉 따라서 뷰포트 근처의 래스터를 먼저 진행할 수 있다!
메인 스레드와 별개로 작동하므로, 부드러운 애니메이션이 가능하다!👍
👉 단, 레이아웃이나 페인트를 다시 계산해야 할 경우에는 메인 스레드가 관여해야 한다..
스크롤 이벤트가 발생할 때마다 GPU로 보낼 다른 합성 프레임을 만든다.
👉 미리 만들어둔 비트맵을 재조합하기만 하면 되기 때문에 쉽고 빠르다고~
🔰 펜딩 트리
아직 화면에 그려지지 않은 최신 프레임 상태를 가지고 있는 트리.
컴포지터 스레드 안에 존재한다.
🕐 액티브 트리
현재 화면에 그려지고 있는 이전 프레임을 그렸던 트리.
최신 정보로 화면을 갱신할 때 이 액티브 트리와 펜딩 트리가 교체된다!
이것도 컴포지터 스레드 안에 존재.
만들어진 합성 프레임이 IPC를 통해 브라우저 프로세스로 전송된다!
이 합성 프레임은 GPu로 전송되어 화면에 디스플레이된다!
앞으로는 합성 프레임이 GPU 프로세스로 바로 보내지는 형태로 변경될 예정이라고...!
HTML문서에서 < img>, < link> 같은 외부 리소스 태그를 먼저 찾아 요청한다!
메인스레드와 동시에 병렬적으로 실행되기 때문에 메인스레드가 html을 전부 파싱하는 속도를 높여준다.