FrontEnd

브라우저의 렌더링 과정

브라우저란?

웹 서버에서 이동하며 쌍방향으로 통신하고 HTML 문서나 파일을 출력하는 GUI 기반의 응용 소프트웨어
브라우저의 주요 기능은 사용자가 선택한 자원을 서버에 요청하고 브라우저에 표시하는 것이다.
자원은 보통 HTML 문서지만 PDF나 이미지 또는 다른 형태일 수 있다.
자원의 주소는 URI(Uniform Resource Identifier)에 의해 정해진다.
브라우저는 HTML과 CSS 명세에 따라 HTML 파일을 해석해서 표시하는데 이 명세는 웹 표준화 기구인 W3C(World Wide Web Consortium)에서 정한다.

브라우저의 구조

  1. 사용자 인터페이스 - 주소 표시줄, 이전/다음 버튼, 북마크 메뉴 등, 웹 페이지 제외 사용자와 상호작용하는 UI
  2. 브라우저 엔진 - 사용자 인터페이스와 렌더링 엔진 사이의 동작을 제어
  3. 렌더링 엔진 - 요청한 컨텐츠를 표시. 예를 들어 HTML을 요청하면 HTML과 CSS를 파싱하여 화면에 표시함.
  4. 통신 - HTTP 요청과 같은 네트워크 호출에 사용됨. 이것은 플랫폼 독립적인 인터페이스이고 각 플랫폼 하부에서 실행됨.
  5. UI 백엔드 - 콤보 박스와 창 같은 기본적인 장치를 그림. 플랫폼에서 명시하지 않은 일반적인 인터페이스로서, OS 사용자 인터페이스 체계를 사용
  6. 자바스크립트 해석기 - 자바스크립트 코드를 해석하고 실행
  7. 자료 저장소 - 이 부분은 자료를 저장하는 계층이다. 쿠키를 저장하는 것과 같이 모든 종류의 자원을 하드 디스크에 저장할 필요가 있다. HTML5 명세에는 브라우저가 지원하는 '웹 데이터 베이스'가 정의되어 있다.

 

웹 브라우저에 URL을 입력하면 벌어지는 일

www.naver.com을 브라우저 주소창에 입력하고 Enter를 쳤다고 가정해보자.

 

1. 입력한 text 정보를 확인

  • 크롬을 비롯한 대부분의 브라우저는 주소창을 검색엔진과 같이 사용한다. (크롬 - 구글 검색)
  • 텍스트가 url 주소일 경우 브라우저 엔진에서 네트워크 호출을 수행한다.
  • 우리는 url인 www.naver.com을 검색했으니 네트워크 호출 단계로 넘어간다.

 

2. 네트워크 호출

 

2.1 IP 주소 찾기

 

우선 브라우저는 www.naver.com의  IP 주소를 찾기 위해 캐시에서 DNS 기록을 확인한다.

 

DNS란?

더보기
DNS(Domain Name System)는 흔히 전화번호부로 비유하곤 한다.
우리가 핸드폰에서 직접 전화번호를 입력하지 않고 연락처에 저장된 이름으로 전화를 걸듯이
DNS역시 해당 도메인 주소와 매핑된 IP번호를 찾아준다.
DNS를 사용하는 이유는 사람들이 쉽게 사이트 주소를 찾을 수 있도록 도와주는 것이다.

도메인 주소가 어떤 IP주소로 연동되어 있는지 확인하는 법

cmd에서 'nslookup 도메인주소' 를 입력하면 해당 도메인 주소의 IP가 나온다.

캐싱된 DNS 기록을 확인하고 해당 도메인 (naver.com) 이름에 맞는 ip 주소(223.130.200.107)이 존재하면,

캐싱된 IP 주소를 반환한다.

만약 캐싱된 DNS 기록에 해당 도메인이 존재하지 않는다면 DNS 서버에 해당 사이트 IP주소를 요청한다.

자세한 동작은 네트워크탭에 DNS의 동작방식이라는 이름으로 따로 포스팅 해보겠다.

 

2.2. HTTP 통신

 

이제 가져온 IP주소로 네이버와 통신이 가능해졌다.
클라이언트인 브라우저는 네이버 서버에 데이터를 요청하는 HTTP Request를 보낸다.
request를 받는 네이버 서버는 이를 byte 형태 (1, 0으로 구성됨) 로 변환하여,
클라이언트로 HTTP Response를 보낸다.
가져온 Response 데이터를 바탕으로 그리기를 시작하는데 이를 렌더링이라 한다.

 

렌더링

 

렌더링이란?

렌더링의 순서를 보여주는 그림

중요 렌더링 경로(Critical Render Path)는 브라우저가 HTML, CSS, Javascript를 화면에 픽셀로 변화시키는 일련의 단계이다.

Critical Render Path는 크게 두 단계로 나뉜다.

  • 브라우저는 읽어온 파일을 파싱하여 어떠한 내용을 페이지에 렌더링 할지 결정하여 RenderTree를 생성한다.
  •  Render Tree를 바탕으로 실제로 렌더링을 진행한다.

렌더링 엔진

webkit main flow
Mozilla's Gecko rendering engine main flow

위에서 다룬 CRP작업을 렌더링 엔진이 수행하게 된다.

브라우저 별로 사용하는 렌더링 엔진이 다른데 사파리는 webkit 크롬은 webkit에서 파생된 blink(현재는 v8) 파이어폭스는 Gecko 엔진을 사용하고 있다. 자세한 정보는 여기를 클릭

 

브라우저의 렌더링 과정

1.파싱

HTML 파싱(Parsing)이란 구문 분석이라고도 불리며, HTML 코드를 토큰(token)으로 분해하고, 토큰으로 이루어진 파스트리(parse tree)를 생성하는 과정이다. 즉 브라우저가 코드를 이해하고 사용할 수 있는 구조로 변환하는 것을 의미한다.

html과 css 모두 아래와 같은 프로세스로 파싱을 진행한다.

Bytes(바이트) -> Chracters(문자열) -> 토큰(Tokens) -> 노드(Nodes) -> 객체 모델(Object Model)

 

1.1 html parsing

 

<html>
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link href="style.css" rel="stylesheet">
        <title>Critical Path</title>
    </head>
    <body>
        <p>Hello <span>web performance</span> students!</p>
        <div><img src="awesome-photo.jpg"></div>
    </body>
</html>
  1. 문자화(Bytes -> Characters) 16진수화된 데이터를 HTML 마크업으로 변환한다.
  2. 토큰화(Chracters -> Token) HTML 마크업을 의미를 가진 각각의 토큰으로 변환한다.
  3. 노드화(Token -> Nodes) 각 토큰들에 관계성을 부여하기 위해 Node로 변경
  4. DOM형성 (Nodes -> DOM) 관계성을 가진 Node들로 DOM 형성

html parsing flow

 

1.2 css parsing

 

body { font-size: 16px }
p { font-weight: bold }
span { color: red }
p span { display: none }
img { float: right }

html parsing과 마찬가지로 바이트는 문자로, 문자는 토큰으로, 토큰은 노드로 변환된다.

이러한 노드를 사용하여 부모-자식 관계가 있는 트리와 같은 구조를 설정한다.

Bytes -> Chracters -> Tokens -> Nodes -> CSSOM

 

css parsing flow

 

1.3 javascript parsing

렌더링 엔진은 HTML 파일을 한줄씩 파싱하며 DOM을 생성한다.

이때 Javascript 코드를 불러오는 script 태그를 만나면 파싱을 잠시 멈춘다.

src 속성에 있는 javascript source코드를 불러와 렌더링 엔진이 아닌 javascript 엔진이 파싱을 담당한다.

JS엔진이 파싱과정을 마치면 다시 제어권을 렌더링엔진에게 돌려주고 파싱을 다시 진행한다.

우리가 script 태그를 body 최하단에 쓰는 이유는 위와 같은 이유에서 이다.

 

JS엔진이 파싱되는 과정은 다음과 같다.

  • Parser에서 AST(Abstract Syntax Tree)로 변환
  • 인터프리터에서 AST기반으로 바이트코드(ByteCode) 생성
  • 인터프리터가 바이트코드를 실행시, 자주 사용하는 함수 및 타입 정보등이 있는 프로파일링 데이터(Profiling data)와 같이 최적화 컴파일러 (Optimizing compiler)에게 보낸다.
  • 최적화 컴파일러는 프로파일링 데이터를 기반으로 최적화된 코드(Optimized code)를 생성한다.
  • 하지만, 프로파일링 데이터 중에 잘못된 부분이 있다면 최적화 해제(Deoptimize)를 하고 다시 바이트코드를 실행해서 이전 동작을 반복한다.

 

 

 

2. Render Tree

DOM트리와 CSSOM 트리를 결합하여, 표시해야 할 순서로 내용을 그려낼 수 있게 렌더 트리(Render Tree)를 형성한다.

이 과정을 Attachement라고 한다.

렌더 트리는 화면에 표시되는 각 노드의 위치를 계산하는 레이아웃에 사용되고 픽셀을 화면에 그리는 페인팅 과정에도 사용된다.

 

DOM과 CSSOM을 결합하여 렌더트리 생성

렌더 트리 생성 과정

  • DOM 트리의 루트부터 노드 각각을 모두 탐색한다.
    • 이 때 화면에 표시되지 않는 일부 노드들(script, meta 태그 등..)은 렌더 트리에서 제외된다.
    • 또한 CSS 속성 중 display:none 같이 화면에서 숨겨지는 속성도 렌더 트리에 반영되지 않는다.
  • 화면에 표시되는 각 노드에 대해 적절하게 일치하는 CSSOM 규칙을 찾아 적용한다.
  • 화면에 표시되는 노드를 콘텐츠 및 계산된 스타일과 함께 렌더트리로 생성된다.

 

3. Layout (reflow)

렌더트리가 준비되면 레이아웃(layout) 또는 리플로우(reflow)라고 하는 단계를 진행할 수 있다.

Layout (reflow)란?

Attachment를 통해 구성한 렌더트리를 통해 표시되어야 하는 노드와 계산된 스타일을 바탕으로 장치의 
viewport내에서 노드의 정확한 위치와 크기를 계산하고 배치하는 단계
이때 상대적인 크기(em, %, rem, vh 등등) 이 px단위로 변환하여 배치된다.
(최신 브라우저의 경우 update Layer Tree 생성)

 

4.paint

paint란?

레이아웃 과정에서 계산된 정보를 바탕으로 각 노드들을 화면에 그려주는 과정
(렌더트리에 적용된 각 노드들로 픽셀단위로 화면에 그리는 과정)
(최신 브라우저의 경우 합성(composite) 단계 발생)
composite : 생성된 Layer들을 합성하여 한장의 비트맵으로 만듦 -> Layer별로 paint 되어 효율성 증가

 

5. Reflow and Repaint

Reflow란?

생성된 DOM 노드의 레이아웃 수치(너비, 높이, 위치 등) 변경 시 영향 받은 모든 노드의 수치를 다시 계산하여 렌더트리를 재생성하는 과정 (화면의 구조 변경시)

Reflow가 발생하는 경우

  • DOM 노드의 추가 또는 제거
  • DOM 노드의 위치 변경
  • DOM 노드의 크기 변경 (margin, padding, border, width, height 등)
  • CSS3 애니메이션과 트랜지션
  • 폰트 변경과(텍스트 내용) 이미지 크기 변경 시(크기가 다른 이미지로 변경)
  • offset, scrollTop, scrollLeft과 같은 계산된 스타일 정보 요청
  • 페이지 초기 랜더링 (최초 layout)
  • 윈도우 리사이징

 

Repaint란?

 

Reflow과정이 끝난 후 재 생성된 렌더 트리를 다시 그리는 과정
화면의 구조가 변경되지 않는 화면 변화의 경우 Repaint만 발생한다. (화면 변경시)
예를 들어 opacity, background-color, visibility, outline 등의 스타일 변경 시에는 Repaint만 동작

reflow나 repaint가 발생하면 렌더링 과정을 다시 거치기 때문에 렌더링에 대한 최적화를 고려해야 한다.

 

렌더링 최적화

최적화를 위해 고려해야 하는 사항

 

1. reflow 최소화

reflow가 일어나면 repaint가 발생하기 때문에 reflow를 최소화하자.

가능하다면 repaint만 발생하는 속성을 사용하자 참조

 

2. css, js 문서를 효율성 있게 작성

 

css 문서 작성시 고려사항

  • <link>, <style>과 같은 css문서는 <head> 태그 안에 배치하기
  • 미디어 유형과 미디어 쿼리활용 (해당 조건에 해당시에만 로드됌)

JS 문서 작성시 고려사항

  HTML 파싱중 <script> 태그를 만나면 DOM생성을 중단하고 javascript가 실행된 후 DOM 생성을 재개함

  • <script>태그를 <body> 최하단에 배치
  • async 속성을 <script> 태그에 부여
  • defer 속성을 <script> 태그에 부여

3. 영향을 주는 노드 최소화

 

노드간 영향이 많은 경우 (애니메이션, 레이아웃 변화 많은 경우)

position absolute 나 fixed를 사용하여 영향받는 노드의 수를 줄일 수 있다.

fixed와 같이 영향을 받는 노드가 전혀 없는 경우 Reflow과정이 없기 때문에 Repaint 연산만 하게 되어 효율적


References By

https://d2.naver.com/helloworld/59361

 

https://velog.io/@thyoondev/웹-브라우저의-동작원리를-알아보자

 

https://velog.io/@jhyun_k/내-화면에-네이버가-켜지는-과정

 

https://aws.amazon.com/ko/blogs/korea/what-happens-when-you-type-a-url-into-your-browser/

 

https://bytesofgigabytes.com/networking/how-http-request-and-response-works/

 

https://velog.io/@khy226/브라우저에-url을-입력하면-어떤일이-벌어질까

 

https://mystudy.tistory.com/21

 

'FrontEnd' 카테고리의 다른 글

JQuery  (0) 2022.12.20
BootStrap  (0) 2022.12.19
Node.js 란?  (0) 2022.12.02