프로그래밍/JavaScript

[JS] 브라우저의 렌더링 과정

mhko411 2021. 8. 3. 09:16
728x90

자바스크립트를 사용하여 DOM 요소를 조작한다. 이때 빈번하게 DOM 요소를 조작한다면 웹 성능이 떨어지기 때문에 최대한 적게 DOM 요소를 조작하거나 조작한 것을 한 번에 렌더하도록 해야한다. 또는 React처럼 Virtual DOM을 활용하여 이전의 DOM 요소들과 비교하여 변경사항만 업데이트하여 웹 성능을 최적화시킬 수 있다.

그렇다면 왜 DOM 요소 조작을 많이하면 웹 성능이 떨어지는지 궁금했고 이를 브라우저의 렌더링 과정을 이해하면서 궁금증을 해결하려고 한다.


브라우저의 기본적인 렌더링 과정을 아래의 순서로 알아본다.

  1. HTML 문서 파싱 및 DOM 생성
  2. CSS 파싱과 CSSOM 생성
  3. 렌더 트리 생성
  4. 자바스크립트 생성
  5. 리플로우와 리페인트

1. HTML 문서 파싱 및 DOM 생성

브라우저(클라이언트)가 서버에 HTML 문서를 요청하면 바이트 형태로 HTML 문서를 응답받는다. 이때 해당 문서에서 정의한 인코딩 방식(UTF-8과 같은)에 따라 기존의 HTML 문서처럼 문자열 형태로 변환한다. 이후 문자열로 된 HTML 문서를 문법적 의미의 최소 단위인 토큰으로 분해한다. 

 

이제 토큰으로 분해된 HTML 문서들이 문서의 객체로 변환하여 각각 노드를 생성한다. 노드가 생성되면 노드들의 관계에 따라 DOM이라는 트리가 생성된다. 아래의 그림처럼 최상위 객체인 document를 시작으로 관계에 따라 DOM이 생성된다.

 

2. CSS 파싱과 CSSOM 생성

위에서 HTML 문서를 분석하여 DOM을 생성하다가 <link> 또는 <style>을 만나게되면 HTML의 DOM 생성을 멈추고 CSS 파일을 로드하거나 <style>에 대한 CSSOM을 생성한다. 과정은 HTML처럼 문자열 변환 -> 토큰 분해 -> 노드 생성 -> CSSOM 생성 순이다.

이때 style에 대한 정보가 늦게 처리된 것부터 먼저 적용된다. 즉 가장 마지막에 처리된 것이 최종적으로 적용되기 때문에 <link>를 통해 받아온 외부 스타일보다 요소에 직접 정의한 인라인 스타일이 적용되는 것이다.

 

3. 렌더 트리 생성

위에서 생성한 DOM과 CSSOM은 렌더링을 하기위해 렌더 트리로 구성된다. 브라우저 화면에 표시되는 것들만 노드로 포함되어 렌더링을 위한 트리가 생성된다. 여기서 브라우저에 화면에 표시가 되지 않는 것은 display: none과 같은 CSS에 의한 스타일이나 <meta>, <script>와 같은 것이다. 이들은 렌더 트리에 포함되지 않는다.

 

렌더 트리가 생성된 이후 렌더 트리를 활용하여 HTML 요소들의 레이아웃을 계산하고 페인트 과정을 통해 최종적으로 브라우저 화면에 출력이된다. 때에 따라 렌더 트리의 구조가 변경되어 레이아웃 계산과 페인트 과정을 다시 진행될 수 있다. 자바스크립트를 통해 요소를 삽입하고 삭제하거나 레이아웃, 스타일 등을 변경할 때 렌더링 과정을 다시 진행하게 된다. 따라서 빈번하게 DOM을 조작하거나 스타일을 변경하는 것은 피해야한다.

 

4. 자바스크립트 생성

DOM을 생성하는 과정은 위에서 아래로 직렬적으로 진행되기 때문에 <script>를 만나면 DOM 생성 과정을 일시적으로 멈추고 자바스크립트를 실행하게된다. 이후 자바스크립트가 모두 실행이되면 다시 DOM을 생성하기 때문에 자바스크립트에서 아직 생성되지 않은 DOM을 조작할 수는 없다. 따라서 <script>를 가장 아래에 추가해주는 것이 좋다. 

 

5. 리플로우와 리페인트

자바스크립트는 DOM API를 통해 DOM 조작을 할 수 있다. DOM 조작으로 노드를 추가 또는 삭제, 스타일 또는 레이아웃 변경 등을 하면 렌더링이 다시 진행된다. 여기서 렌더 트리가 변경되고 변경된 렌더 트리를 기반으로 레이아웃, 페인트 과정이 진행되는데 이를 리플로우와 리페인트라고 한다.

 

리플로우는 레이아웃에 대한 계산을 다시 진행하는 것이며 리페인트는 렌더 트리와 계산된 레이아웃을 통해 브라우저 화면에 다시 페인트하는 것을 말한다. 이때 레이아웃에 대한 변경은 진행되지 않았을 때는 리플로우없이 리페인트만 진행될 수도 있다.


오늘은 브라우저의 렌더링 과정을 알아봤다. 렌더링 과정을 이해하고 있다면 디버깅하는데 많은 도움이 될 것 같다. 

'프로그래밍 > JavaScript' 카테고리의 다른 글

[ES6] Promise  (0) 2021.08.12
[ES6] 제너레이터  (0) 2021.08.04
[JS] 함수  (0) 2021.07.19
[JS] Closure  (0) 2021.07.10
[JS] 실행 컨텍스트  (0) 2021.07.07