자바스크립트 딥다이브 - 브라우저의 렌더링 과정

ChoiYongHyeun·2023년 12월 25일
0

대부분 프로그래밍 언어는 운영체제나 가상 머신 위에서 실행되지만

웹 애플리케이션 클라이언트 사이드 자바스크립트는 브라우저에서 HTML , CSS 와 함께 실행된다.

따라서 브라우저 환경을 고려할 때 더 효율적인 프로그래밍이 가능하다.

브라우저가 HTML , CSS , 자바스크립트로 작성된 텍스트 문서를 어떻게 파싱하여 렌더링 하는지 살펴보자

파싱

텍스트 문서의 문자열을 token 으로 분해하고, 문법적 의미와 구조를 반영하여 트리구조의 자료구조인 parse tree / sysntax tree 를 생성하는 일련의 과정을 의미한다.

일반적으로 파싱이 완료된 후에는 중간 언어인 bytecode를 생성하고 실행한다.

렌더링

파싱 된 parse tree 를 이용하여 다음과 같은 가정으로 렌더링 한다.

  1. 브라우저는 HTML , CSS , 자바스크립트, 이미지, 폰트 파일 등 렌더링에 필요한 리소스를 요청하고 응답을 받는다.

  2. HTML 을 파싱하여 DOM , CSS 를 파싱하여 CSSOM 을 생성하고 이를 결합하열 렌더 트리를 생성한다.

  3. 자바스크립트 엔진은 서버로부터 자바스크립트를 파싱하여 AST (Abstract Syntax tree)를 생성하고 바이트 코드로 변환하여 실행한다. 이 때 자바스크립트는 동적으로 DOM , CSSOM 을 변경 할 수 있으며 변경된 DOM , CSSOM 은 렌더 트리로 다시 결합된다.

  4. 렌더 트리를 기반으로 HTML 요소의 레이아웃을 계산하고 브라우저 환경에 HTML 요소를 페인팅 한다.

요청과 응답

요청과 응답에 대한 자세한 내용은 HTTP 공부 시리즈를 통해 보도록 하자

브라우저의 요청과 응답은 개발자 도구 - network 에서 살펴 볼 수 있는데 이를 보면 index.html 에 해당하는 www.naver.com 뿐이 아니라 부수적인 많은 것들도 요청과 응답을 받은 모습을 볼 수 있다.

이는 브라우저 렌더링 엔진이 index.html을 파싱하는 도중 외부 리소스를 로드하는 태그 link , a , script 등을 만나면 HMTL 파싱을 중단하고 해당 리소스 파일들도 서버로 요청을 보내기 때문이다.

HTTP 1.1HTTP 2.0

이 내용도 HTTP 공부 에서 자세히 살펴보기로 하고 간단히 말 하면

HTTP 1.1 은 요청과 응답이 하나씩만 가능한 1:1 대응이였지만 HTTP 2.0 부터는 N:N 대응으로 렌더링 속도가 더욱 빨라졌다.

HTMLDOM 생성

브라우저 요청에 의해 서버가 응답한 HTML 문서는 문자열로 이뤄진 순수한 텍스트이다.

순수한 텍스트를 브라우저에 시각적인 픽셀로 시각화 하려면 브라우저가 이해 할 수 있는 자료구조로 변환하여 메모리에 저장해야 한다.

  1. 서버는 브라우저가 요청한 HTML 파일을 읽어들여 메모리에 저장한 후 메모리에 저장된 바이트(2진수)를 네트워크를 경유하여 응답한다.
  2. 브라우저는 서버가 응답한 HTML 문서를 바이트(2진수) 형태로 응답 받는다. 응답된 바이트 형태의 HTML 문서는 meta 태그의 charset 어트리뷰트에 의해 지정된 인코딩 방식으로 문자열로 변환된다.
  3. 문자열로 변환된 HTML 문서를 문법적 의미를 갖는 코드의 최소 단위인 토큰으로 분해한다.
  4. 토큰들을 객체로 생성하여 노드 를 생성한다. (문서 노드 , 요소 노드 , 어트리뷰트 노드 , 텍스트 노드) 이 노드들은 DOM 을 구성하는 기본 요소가 된다.
  5. HTML요소는 부모 자식 형제 관계를 갖는 중첩 관계를 갖는다. 이런 관계를 반영하여 트리 자료 구조로 구성하고 이렇게 구성된 트리 자료 구조를 DOM 이라 부른다.

DOMHTML 문서를 파싱한 결과물이다.

CSSCSSOM 생성

위와 동일

렌더 트리 생성

파싱 하여 만든 자료구조인 DOMCSSOM은 렌더링을 위해 렌더 트리로 결합된다.

화면에 렌더링 되지 않는 노드 (meta , display : none , script 태그)를 제외하고 생성한다.

즉 렌더 트리는 브라우저에 렌더링 되는 노드만으로 구성된다.

구성한 렌더 트리를 가지고 Layout -> paint 단계를 통해 브라우저에 렌더링 한다.

렌더링 과정은 다음과 같은 경우 반복 실행된다.

  1. 자바스크립트에 의한 노드 추가 및 삭제
  2. 뷰포트의 크기 변경
  3. HTML 요소의 레이아웃을 변경을 발생 시키는 스타일 변경

자바스크립트 파싱과 실행

DOM 은 HTML 문서를 파싱한 결과물로, 이러한 자료구조를 통해 HTML 요소와 스타일을 변경 할 수 있는 프로그래밍 인터페이스로 DOM API 를 제공한다.

자바스크립트에서는 document 라는 객체를 통해 DOM 에 접근하여 수정하거나 추가, 제거 할 수 있다.

HTML 파싱 도중 script 태그를 만나면 HTML 파싱을 중단 하고 script 에 담긴 자바스크립트를 파싱 및 실행한다.

자바스크립트의 파싱 및 실행이 종료되면 HTML 파싱을 재개한다.

자바스크립트의 파싱은 브라우저의 렌더링 엔진이 아닌 브라우저 별 자바스크립트 엔진이 파싱한다.

다음과 같은 단계를 따른다.

토크나이징

단순한 문자열인 자바스크립트 소스 코드를 어휘 분석 하여 문법적 의미를 갖는 코드의 최소 단위인 토큰들로 분해한다.

파싱

토큰들의 집합을 구문 분석 하여 AST (Abstact Syntax tree , 추상적 구문 트리)를 생성한다.

function isOddes(arr) {
  arr.forEach((num) => {
    if (num % 2) return true;
    return false;
  });
}

const arr = [1,2,3,4,5]
isOddes(arr)

다음과 같은 소스코드를 이용해 AST 를 만들면

{
  "type": "Program",
  "start": 0,
  "end": 142,
  "loc": {
    "start": {
      "line": 1,
      "column": 0
    },
    "end": {
      "line": 9,
      "column": 12
    }
  },
  "comments": [],
  "range": [
    0,
    142
  ],
  "sourceType": "module",
  "body": [
    {
      "type": "FunctionDeclaration",
      "start": 0,
      "end": 104,
      "loc": {
        "start": {
          "line": 1,
          "column": 0
        },
        ....

다음과 같은 파싱을 거쳐 자료구조인 트리를 생성한다.

파싱의 결과물로 생성된 AST 는 인터프리터가 실행 할 수 있는 중간 코드인 바이트 코드로 변환되고 인터프리터에 의해 실행된다.

리플로우와 리페인트

자바스크립트 코드에 의해 DOM , CSSOM을 변경하는 DOM API 가 사용된 경우 렌더 트리가 변경되며 브라우저의 화면이 다시 렌더링 된다.

이를 Reflow , Repaint 라고 한다.

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

HTML 요소를 파싱하다가 자바스크립트를 파싱해야 하면 HTML 파싱을 중단하고 자바스크립트를 우선적으로 파싱한다고 하였다.

따라서 자바스크립트 파싱을 의미하는 script 태그의 위치는 중요한 의미를 갖는다.

또한 파싱 된 자바스크립트의 AST 는 여태 파싱 된 DOMDOM API를 통해 조작하는데, 생성이 되지 않은 DOM 의 노드에 접근하는 것은 불가능하기 때문에 더더욱 script 태그의 위치는 중요하다.

이러한 문제를 해결하기 위해 body 태그 뒤에 script 태그들을 위치시키는 것은 좋은 아이디어이다.

페이지 렌더링 시간이 빨라질 뿐더러 (렌더링이 우선적으로 종료되어 브라우저에 렌더링 됨으로) 생성되지 않은 DOM 의 노드에 접근하려고 하는 에러를 방지 할 수 있다.

더 보면 좋을 아티클

게시글을 작성 후에 관련 주제들이 하단에 나오는데 나보다 훨씬 많은 내용을 정리한 링크가 있어 공유한다.

🌏 내 화면에 네이버가 켜질 때까지 - 브라우저 렌더링 과정

profile
빨리 가는 유일한 방법은 제대로 가는 것이다

0개의 댓글