[JavaScript] 브라우저 렌더링

Letmegooutside·2022년 1월 30일
0

JavaScript

목록 보기
23/25
post-thumbnail

브라우저 렌더링

HTML, CSS, 자바스크립트 등 개발자가 작성한 문서가 브라우저에서 출력되는 과정

브라우저마다 다르지만, 브라우저는 렌더링을 수행하는 렌더링 엔진을 가지고 있다.
(크롬 : 블링크(Blink), 사파리 : 웹킷(Webkit), 파이어폭스 : 개코(Gecko))

렌더링 과정

사용자가 브라우저를 통해 웹사이트에 접속하면, 서버로부터 HTML, CSS등 웹 사이트에 필요한 리소스를 다운로드 받는다.
브라우저가 페이지를 렌더링하려먼 먼저 HTML 코드는 DOM, CSS는 CSSOM 트리를 생성해야 한다.

1. DOM 트리 생성

다음은 HTML 코드가 DOM 트리로 변환되는 과정이다.

  1. 변환 : 브라우저가 HTML의 원시 바이트를 읽어와서, HTML에 정의된 인코딩(예:UTF-8)에 따라 개별 문자로 변환한다.
  2. 토큰화 : 브라우저가 문자열을 W3C 표준에 지정된 고유 토큰으로 변환한다.
  3. 렉싱 : 방출된 토큰은 해당 속성 및 규칙을 정의하는 객체로 변환된다.
  4. DOM 생성 : HTML 마크업에 정의된 여러 태그 간의 관계를 해석해서 트리 구조로 연결한다.

브라우저는 HTML 마크업을 처리할 때 마다 위의 모든 단계를 수행한다.

2.CSSOM 트리 생성

HTML 마크업 내에 직접 스타일을 선언할 수도 있지만, head 태그에 외부 css파일을 참조하거나, head태그에 style태그를 정의할 수도 있다.

HTML과 마찬가지로, 외부 css파일에 정의된 스타일과 style태그에 작성된 스타일을 브라우저가 이해하고 처리할 수 있는 형식으로 변환해야 하한다.

DOM트리를 생성하는 과정과 동일한 과정으로 CSSOM트리를 생성한다.

이런 과정을 거쳐서 마지막으로 CSSOM(CSS Object Model)이라는 트리 구조가 생성된다.

자바스크립트 파싱

자바스크립트 파싱은 CSS파싱과 마찬가지로 렌더링 엔진이 HTML문서를 한 줄 씩 읽어나가다 script태그를 만나면 자바스크립트 엔진으로 제어권을 넘기며 시작된다.

자바스크립트 엔진은 CPU가 이해할 수 있는 저수준 언어로 자바스크립트 코드를 파싱하고 DOM, CSSDOM과 같은 AST(추상적 구문 트리)를 생성하여 이를 기반으로 바이트코드를 생성하고 인터프리터가 실행될 수 있도록 만든다.

3. 렌더링 트리 (Rendering Tree) 생성

DOM 트리와 CSSOM 트리가 만들어지면, 이 둘을 결합해서 렌더링 트리를 생성한다.
렌더링 트리에는 페이지를 렌더링 하는데 필요한 노드만 포함된다.

4. 레이아웃 (Layout) 단계

레이아웃 단계에서는 뷰포트 내 각 요소의 정확한 위치와 크기를 캡쳐하는 Box 모델이 출력된다.
모든 상대적인 측정 값은 화면에서 절대적인 픽셀로 변환된다.

뷰포트 : 웹페이지가 사용자에게 보여지는 영역

5. 페인팅 단계

렌더링 트리의 각 노드를 화면의 실제 픽셀로 변환하게 된다.
레이아웃 단계에서 모든 계산이 완료가 되면, 화면에 요소를 그리게 된다.
이 단계를 페인팅 또는 래스터화라고 한다.

이미 레이아웃 단계에서 각 노드들의 위치, 크기, 색상 등 스타일이 모두 계산이 되었기 때문에 화면에 실제 픽셀로 변환할 수 있게 된다.

리플로우(Reflow), 리페인트(Repaint)

사용자가 웹페이지에 처음 접속하면, 렌더링 과정을 거쳐서 화면에 모든 요소가 그려지게 된다.
이후 사용자는 다양한 액션을 수행하게 되고, 여기서 발생되는 이벤트로 인해 새로운 HTML요소가 추가되거나 기존 요소의 스타일이 바뀔 수 있다.
이런 변경을 통해 영향을 받게되는 모든 노드에 대해 렌더링 트리 생성과 레이아웃 과정을 다시 수행하게 되는데 이러한 과정을 리플로우라고 한다.

리플로우는 단지 변경사항을 반영하기 위해서 렌더링 트리를 생성하고 레이아웃 과정을 다시 수행하는 것이고, 실제 이 결과를 화면에 그려지게 하기 위해서는 다시 페인팅 단계를 수행해야 하는데 이 과정을 리페인트라고 한다.

  • 리플로우 : 변경 사항을 반영하기 위해 렌더링 트리 생성, 레이아웃 과정을 다시 수행
  • 리페인트 : 리플로우된 결과를 화면에 그려지게 하기 위해 다시 페인팅 단계를 수행

기존 요소에 변경사항이 생겼다고 해서 항상 리플로우-리페인트가 일어나는 것은 아니고, 레이아웃에 영향을 미치지 않는 단순한 색상 변경사항은 리플로우 수행없이 바로 리페인트만 수행하기도 한다.
단 리플로우가 발생하면, 리페인트는 반드시 일어난다.

  • 리플로우가 일어나는 대표적인 속성
    position, width, height, margin, padding, border, border-width, font-size, font-weight, line-height, text-align, overflow

  • 리페인트만 일어나는 대표적인 속성
    background, color, text-decoration, border-style, border-radius

자바스크립트 파싱에 의한 HTML 파싱의 중단

렌더링 엔진과 자바스크립트 엔진 코도는 직렬적으로 파싱하게 된다.
즉 위에서 아래로 한 줄씩 동기적으로 읽는다는 의미이다.

<!DOCTYPE html> 
 <html>  
  <head>   
   <meta charset="UTF-8">
   <link rel="stylesheet" href="style.css"> //HTML 파싱 중단 > CSS 파싱 
   <script src="app.js"></script> //HTML 파싱 중단 > 자바스크립트 파싱/실행 
    ...

script 태그가 위의 코드와 같이 헤드 안에 있을 경우 다음과 같은 문제가 발생한다.

  • DOM이 완성되지 않은 상태에서 자바스크립트 코드가 DOM API를 통해 DOM을 조작하면 에러가 발생할 수 있다.
  • 자바스크립트의 로딩, 파싱, 실행으로 인해 페이지의 로딩 시간이 길어질 수 있다.

따라서 script코드는 DOM이 모두 생성된 후 파싱,실행될 수 있도록 아래와 같이 body의 가장 하단에 적어주면 DOM조작 시 오류가 없고, HTML 파싱이 블로킹 없이 실행되어 페이지 로딩시간이 단축된다.

Script 태그의 async/defer 어트리뷰트

자바스크립트 파싱에 의한 HTML 파싱 블로킹 현상을 근본적으로 해결하기 위해 HTML5 부터 async와 defer어트리뷰트가 추가되었다.

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

두 어트리뷰트 모두 HTML파싱과 외부 자바스크립트 파일의 로드가 비동기적으로 동시에 진행되도록 만들어준다.
하지만 두 어트리뷰트 사이에는 자바스크립트 실행 시점의 차이가 존재한다.

async

  • HTML 파싱과 외부 자바스크립트 파일의 로드가 비동기적으로 동시에 진행된다.
  • 자바스크립트의 파싱과 실행은 자바스크립트 파일이 로드되면 바로 진행되며 이 떄 HTML 파싱이 중단된다.

defer

  • HTML 파싱과 외부 자바스크립트 파일의 로드가 비동기적으로 동시에 진행된다.
  • 자바스크립트 파싱과 실행은 HTML파싱이 완료되어 DOM이 생성된 이후에 진행된다. 따라서 DOM 생성이 완료된 이후 실행되어야 하는 자바스크립트 파일에 유용하게 사용할 수 있다.




Reference
https://medium.com/개발자의품격/브라우저의-렌더링-과정-5c01c4158ce
https://devcecy.com/브라우저는-어떻게-렌더링-될까/

0개의 댓글