38 브라우저 렌더링 과정

리소스 요청 및 응답
브라우저는 HTML, CSS, JS, 이미지, 폰트파일 등 렌더링에 필요한 리소스를 요청하고, 서버로부터 응답을 받는다.
- 브라우저 창에 URL를 입력함: https://search.naver.com/search.naver?sm=tab_hty.top&where=nexearch&query=검색창&oquery=23123&tqi=h9Hmusp0JywsscwBK2NssssssfZ-229440
- URL이 DNS를 거쳐 IP주소로 변환되고, 해당 IP주소에 해당하는 서버로 요청이 전송됨
- 요청한 HTML파일이 도착하고, 해당 HTML을 파싱하는 과정에서 외부 리소스를 필요로 하는 태그(img, link, script)를 만나면 해당 파일들을 요청하여 응답받는다.
HTML 파싱과 DOM 생성
HTML와 CSS를 파싱하여 DOM과 CSDOM을 생성하고 이들을 결합하여 렌더트리를 생성한다.
HTML은 문자열로 이뤄진 순수 텍스트임
이를 렌더링 하려면 브라우저가 이해할 수 있는 자료구조, 객체로 변환하여 메모리에 저장해야함
- 서버로부터 바이트 형태의 HTML문서가 도착함
- 전송된 바이트를 문자열로 변환(meta태그의 charset에 의해 지정된 인코딩 방식으로 변환됨)
- 문자열 상태인 HTML문서를 읽어 문법적 의미를 갖는 토큰으로 변환함
- 토큰들이 객체형태인 노드로 변환됨
- 문서, 요소, 어트리뷰트, 텍스트노드로 나뉨
- 노드는 DOM 구성 기본요소
- HTML문서는 각 요소로 이뤄지며 각 요소는 중첩관계를 맺음. 따라서 이들 사이에는 부자관계가 생성됨. 이를 반영하여 트리 자료구조로 구성함 이 트리 자료구조를 DOM이라 부름

CSS 파싱과 CSSOM 생성
렌더링 엔진은 DOM을 생성해나가다가 CSS를 로드하는 link나 style 태그를 만나면 DOM생성을 일시중지하고 해당 파일을 서버에 요청함
해당 파일을 동일한 파싱과정을 거쳐 CSSOM(CSS Object Model)로 만듦
CSS파싱이 완료되면 HTML파싱이 중단된 지점부터 다시 HTML을 파싱하기 시작하여 DOM 생성을 재개함
CSSOM은 CSS의 상속을 반영하여 생성됨 → 상단 객체에서 하단 객체로 프로퍼티가 상속됨
렌더트리 생성
만들어진 DOM과 CSSOM을 결합하여 렌더트리로 결합함
렌더링을 위한 트리구조 → CSS에 의해 비표시 되거나 화면에 렌더링 되지 않는 노드들은 포함되지 않음
이렇게 만들어진 렌더트리는 HTML요소의 레이아웃을 계산하는데 사용됨 → 페인팅 처리에 입력됨
레이아웃 계산과 페인팅
해당 과정은 아래의 경우가 일어나면 계속해서 재실행됨
- JS에 의한 노드 추가 또는 삭제
- 브라우저 창의 리사이징에 의한 뷰포트 크기 변경
- HTML요소 레이아웃 변경을 발생시키는 스타일 변경
⇒ 레이아웃 계산과 페인팅은 비용이 많이드는, 성능에 악영향을 미치는 작업이라 리렌더링이 빈번하지 않게 하는 것이 중요함
Javascript 파싱과 실행
브라우저 JS엔진은 JS를 파싱하여 AST(Abstract Syntax Tree)를 생성하고 바이트 코드로 변환하여 실행한다. 이때 JS는 DOM API를 사용하여 DOM이나 CSDOM을 변경할 수 있다. 변경된 DOM과 CSDOM은 다시 렌더트리로 결합된다.
HTML파싱중 script태그를 만나면 DOM생성을 일시 중단한다.
그리고 해당 js파일을 서버에 요청하며, 받은 js파일을 파싱하기 위해 js엔진에 주도권을 넘긴다.
이후 파싱과 실행이 종료되면 HTML파싱을 진행했던 부분부터 다시 수행한다.
JS실행은 브라우저 렌더링 엔진이 아닌 JS엔진이 처리한다.
JS엔진은 JS코드를 파싱하여 저수준 언어(바이트코드)로 변환하여 실행한다.
이 중간에 AST(추상적 구문 트리)를 만든다. 그리고 AST를 기반으로 인터프리터가 실행할수 있는 중간 코드인 바이트 코드를 생성하여 실행한다.
- 소스코드 ⇒ 토크나이저에 의해 토크나이징(최소 문법단위인 토큰으로 분해)
- 토큰 ⇒ 파서에 의해 파싱
- AST AST를 통해 프리티어, 타입스크립트, 바벨도 구현한다.⇒ 바이트코드 생성기에 의해 바이트 코드 생성
- 바이트코드 => 인터프리터에 의해 실행
리플로우와 리페인트
JS에 의해 DOM이나 CSSOM이 변경하는 DOM API가 사용된 경우 DOM과 CSSOM은 변경된다.
이때 변경된 DOM과 CSSOM은 다시 렌더트리로 결합하고, 변경된 렌더트리를 기반으로 레이아웃과 페인트과정을 거쳐 리렌더링된다.
레이아웃 계산을 리플로우
페인트 과정을 리페인트
라 한다.
자바스크립트 파싱에 의한 HTML 파싱 중단
HTML 문서 body 중간에 script가 오는 경우, 동기적으로 실행되기 때문에 해당 DOM이 없어서 오류가 발생할 수 있다.
</body> 이후에 <script> 로 불러오자
script태그의 async defer 어트리뷰트
async와 defer 어트리뷰트를 사용하면 HTML파싱과 외부 js파일 로드가 비동기적으로 동시에 진행된다.
async
HTML파싱과 외부 js파일 로드가 비동기적으로 동시에 일어난다.
js파일 로드가 완료되는 즉시, js가 실행되며 HTML파싱이 중단된다.
만약 여러개의 js 파일을 요청하는 경우, 순서랑 상관없이 가장 먼저 도착한 애가 먼저 실행된다.
defer
마찬가지로 비동기적으로 로드가 진행되나, HTML파싱이 완료된 직후에 js코드가 실행된다.