개인공부/모던 자바스크립트 Deep Dive

38장 브라우저의 렌더링 과정

강물둘기 2023. 1. 27. 11:03

* 아래 내용은 이웅모 저자님의  모던 자바스크립트 Deep Dive 책(위키북스)을 정리한 내용입니다.

   저작권에 문제가 된다면 삭제하도록 하겠습니다.

 

 

브라우저는 다음과 같은 과정을 거쳐 렌더링을 수행한다.

⓵ 브라우저는 렌더링에 필요한 리소스(HTML,CSS,Javascript,이미지,폰트파일 등)를 요청하고 서버로부터 응답받는다.

⓶ 브라우저의 렌더링 엔진은 서버로부터 받은 HTML, CSS를 파싱하여 DOM과 CSSOM을 생성하고 결합하여 렌더 트리를 생성한다.

⓷ 브라우저의 Javascript 엔진은 Javascript를 파싱하여 AST를 생성하고 바이트코드로 변환하여 실행한다. 이때 Javascript는 DOM API를 통해 DOM이나 CSSOM을 변경할 수 있다. 변경된 DOM과 CSSOM은 다시 렌더 트리로 결합된다.

⓸ 렌더 트리를 기반으로 HTML요소의 레이아웃(위치와 크기)을 계산하고 브라우저 화면에 HTML요소를 페인팅한다.

 

1. 요청과 응답

브라우저 렌더링에 필요한 리소스는 모두 서버에 존재하므로 필요한 리소스를 서버에 요청해야 한다.

브라우저 주소창에 URL을 입력하고 엔터 키를 누르면 URL의 호스트 이름이 DNS를 통해 IP주소로 변환되고 이 IP 주소를 갖는 서버에게 요청을 전송한다.

출처 : https://hanseul-lee.github.io/2020/12/24/20-12-24-URL/

 

Javascript를 통해 동적으로 서버에 정적/동적 데이터를 요청할 수도 있다.(43장, 44장 참조)

 

2. HTTP

HTTP(HyperText Transfer Protocol)는 웹에서 브라우저와 서버가 통신하기 위한 프로토콜(규약)이다.

기존버전인 HTTP/1.1 은 커넥션당 하나의 요청과 응답만 처리했는데, 2015년에 추가된 HTTP/2는 커넥션당 여려 개의 요청과 응답이 가능해져서 페이지 로드 속도가 약 50% 정도 빨라졌다.

 

3. HTML 파싱과 DOM 생성

브라우저의 렌더링 엔진은 응답받은 HTML 문서를 파싱하여 브라우저가 이해할 수 있는 자료구조인 DOM(Document Object Model)을 생성한다.(DOM은 39장 참조)

 

파싱과정 : 바이트 -> 문자 -> 토큰 -> 노드 -> DOM

DOM 출처 : 위키백과

 

4. CSS 파싱과 CSSOM 생성

렌더링 엔진은 HTML을 처음부터 한 줄씩 순차적으로 파싱하여 DOM을 생성해 나가다가 CSS를 로드하는 link 태그나 style 태그를 만나면 DOM 생성을 일시 중단한다.

CSS나 style 태그 내의 코드를 HTML과 동일한 파싱 과정(바이트 -> 문자 -> 토큰 -> 노드 -> CSSOM)을 거쳐 CSSOM(CSS Object Model)을 생성한다. CSS 파싱을 완료하면 HTML 파싱이 중단된 지점부터 다시 파싱을 시작한다.

CSSOM 출처 : https://lee-hyuna.github.io/2017/12/20/Web/cssom/

 

5. 렌더 트리 생성

DOM과 CSSOM은 렌더링을 위해 렌더 트리(render tree)로 결합된다.

브라우저 화면에 렌더링되지 않는 노드(meta태그, script태그 등)와 CSS에 의해 비표시(display:none)되는 노드들은 포함하지 않는다.

완성된 렌더 트리는 각 HTML 요소의 레이아웃(위치와 크기)을 계산하는 데 사용되며 브라우저 화면에 픽셀을 렌더링하는 페인팅처리에 입력된다.

 

6. Javascript 파싱과 실행

DOM은 HTML 요소와 스타일 등을 변경할 수 있는 DOM API를 제공한다. Javascript 코드에서 DOM API를 사용하여 DOM을 동적으로 조작할 수 있다.(39장 참조)

 

HTML을 한 줄씩 파싱해 나가다가 script 태그를 만나면 파싱을 중단하고 javascript 엔진에 제어권을 넘긴다.

javascript 엔진은 javascript 코드를 파싱하여 CPU가 이해할 수 있는 저수준 언어로 변환하고 실행하는 역할을 한다.

 

렌더링 엔진으로부터 제어권을 넘겨받은 javascript 엔진은 javascript 코드를 파싱하기 시작하여 AST(Abstract Syntax Tree)를 생성한다. 그리고 AST를 기반으로 인터프리터가 실행할 수 있는 중간 코드인 바이트코드를 생성하여 실행한다.

출처 : 자바스크립트 Deep Dive, 위키북스

 

7. 리플로우와 리페인트

Javascript 코드에 DOM API가 사용되는 경우 DOM이나 CSSOM이 변경된다. 이때 변경된 DOM과 CSSOM은 다시 렌더 트리로 결합되고 변경된 렌더 트리를 기반으로 레이아웃과 페인트 과정을 거쳐 브라우저의 화면에 다시 렌더링한다.

이를 리플로우(reflow), 리페인트(repaint)라고 한다.

리플로우와 리페인트가 반드시 순차적으로 동시에 실행되는 것은 아니다. 레이아웃에 영향이 없는 변경은 리플로우 없이 리페인트만 실행된다.

 

8. Javascript 파싱에 의한 HTML 파싱 중단

렌더링 엔진과 Javascript 엔진은 직렬적으로 파싱을 수행한다. 이것은 script 태그의 위치에 따라 HTML 파싱이 블로킹되어 DOM 생성이 지연될 수 있다는 것을 의미한다. 따라서 script 태그의 위치는 중요한 의미를 갖는다.

script 태그를 HTML 문서 상단이나 중간에 넣게 되면 아직 생성되지 않는 요소들을 javascript 코드에서 사용할 경우 오류가 발생할 수 있다.

이러한 문제를 회피하기 위해 body요소 가장 아래에 script태그를 위치 시키는 것을 권장한다. 이렇게 하면 DOM이 완성되지 않은 상태에서 javascript 코드가 DOM을 조작하는 에러가 발생할 우려도 없고, javascript 코드가 실행되기 이전에 DOM생성이 완료되어 렌더링되므로 페이지 로딩 시간이 단축되는 이점도 있다.

 

9. script 태그의 async/defer 어트리뷰트

앞에서 본 javascript 파싱에 의한 DOM 생성이 중단되는 문제를 근본적으로 해결하기 위해 HTML5부터 script 태그에 async와 defer 어트리뷰트가 추가되었다.

<script async src="extern.js"></script>
<script defer src="extern.js"></script>

async 와 defer 어트리뷰트를 사용하면 HTML 파싱과 외부 javascript 파일의 로드가 비동기적으로 동시에 진행된다.

async 어트리뷰트의 javascript 파싱과 실행은 javascript 파일의 로드가 완료된 직후 진행되며 이 때 HTML 파싱이 중단된다.

defer 어트리뷰트의 javascript 파싱과 실행은 HTML 파싱이 완료된 직후(DOM 생성이 완료된 직후) 진행된다.

 

출처 : https://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html

 

 

 

 

 

 

Reference

- 이웅모 ,  모던 자바스크립트 Deep Dive , 위키북스 , 2020