모던 자바스크립트 Deep Dive의 브라우저 렌더링 과정을 읽고 내용을 정리한다.
웹 앱에서 자바스크립트는 브라우저에서 html, css와 함께 실행된다.
브라우저 환경을 고려할 때 더 효율적인 자바스크립트 프로그래밍이 가능하다. 그러니 알아두어야겠찌,,,,
들어가기 전에
익숙치 않은 단어 (또는 알지만 설명하라고하면 잘 못하겠는, 안다고 말하기 좀 애매한) 가 나오기 때문에 간략하게 정리하고 가려고 한다.
이미 아는 단어들이라면 넘어가도 좋을듯.
파싱
프로그래밍 언어의 문법에 맞게 작성된 텍스트문서를 읽어 실행하기 위해 텍스트 문서의 문자열을 토큰으로 분해하고, 토큰에 문법적 의미와 구조를 반영해 트리구조의 자료구조인 파스트리를 생성하는 일련의 과정
렌더링
html, css, 자바스크립트로 작성된 문서를 파싱하여 브라우저에 시각적으로 출력하는 것
CSSOM(CSS Object Model)
CSS 스타일 규칙을 JavaScript에서 접근할 수 있도록 트리 구조로 표현한 것
AST (Abstract Syntax Tree)
자바스크립트 코드의 구조를 트리 형태로 표현한 것
브라우저 렌더링 과정
본격적으로 브라우저가 html, css, 자바스크립트를 파싱하여 브라우저에 렌더링하는 과정을 자세히 살펴보자.
렌더링에 필요한 리소스를 서버에 요청하고 응답받기
브라우저는 html, css, 자바스크립트, 이미지, 폰트 파일 등 렌더링에 필요한 리소스를 서버에 요청하고 응답 받는다.
렌더링에 필요한 모든 소스는 서버에 존재하기 때문에 필요한 리소스를 서버에 요청하고, 서버가 응답한 리소스를 렌더링한다.
브라우저의 렌더링 엔진이 html을 파싱하는 도중 외부 리소스를 로드하는 태그(link, img, script 태그 등)을 만나면 html 파싱을 일시 중단하고 해당 리소스 파일을 서버로 요청한다.
DOM 생성
html 문서는 문자열로 이루어진 순수한 텍스트기 때문에, 브라우저가 이해할 수 있는 자료구조(객체)로 변환하여 메모리로 저장해야 한다.
서버는 브라우저가 요청한 html 파일을 읽고 메모리에 저장한 다음, 메모리에 저장된 바이트(2진수)를 인터넷을 경유하여 응답한다.
응답된 바이트(2진수)형태의 html 문서는 meta 태그의 charset 속성에 선언된 인코딩 방식이 응답 헤더에 담겨 브라우저가 이를 확인하고 문자열로 변환한다.
문자열로 변환된 html문서를 읽어 토큰으로 분해하고, 각 토큰을 객체로 변환하여 노드들을 생성하여 DOM을 구성하는 기본 요소가 된다.
즉, html 요소 집합으로 이루어지며 중첩관계를 갖고 부자관계가 형성 되는데, 요소 간 부자관계를 반영하여 모든 노드들을 트리 자료구조로 구성한 것이 DOM이다. 렌더링 엔진은 맨 윗줄부터 순차적으로 파싱하여 DOM을 생성한다.
CSSOM 생성
link태그를 만나면 DOM생성을 잠깐 멈추고 CSS 파일을 서버에 요청하여 HTML과 동일한 파싱과정을 거친다(바이트 - 문자열 - 토큰 - 노드 CSSOM). CSSOM 생성을 마치면 다시 html 파싱이 중단된 지점부터 마저 파싱한다.
렌더트리 생성
브라우저의 렌더링 엔진은 서버로부터 응답된 html과 css를 파싱하여 DOM과 CSSOM을 생성하여 결합해서 렌더트리를 생성한다.
렌더트리는 렌더링을 위한 트리구조의 자료구조로, 브라우저 화면에 렌더링되는 노드만 구성해서 완성한다.
브라우저 화면에 렌더링되지 않는 노드(meta, script 태그 등)와 CSS에 의해 표시되지 않는 노드(display:none)는 렌더트리에 포함되지 않는다.
완성된 렌더트리는 각 html 요소의 위치와 크기를 계산하는데 사용되고, 브라우저 화면에 픽셀을 렌더링하는 페인팅 처리에 입력된다.
1. 자바스크립트의 의한 노드 추가 / 삭제
2. 브라우저 창의 리사이징에 의한 뷰포트 크기 변경
3. html요소의 레이아웃 크기 변경을 발생시키는 스타일 변경 등은
브라우저 렌더링 과정이 반복해서 실행될 수 있다. -> 계산과 페인팅을 다시 실행 (리렌더링) 해야 하기 때문에 성능에 악영향을 준다.
자바스크립트 파싱과 실행
DOM은 html 문서 구조 정보 및 DOM API를 제공한다. DOM API을 이용하면 이미 생성된 DOM을 동적으로 조작할 수 있다.
렌더링 엔진은 css 파싱 과정과 마찬가지로 DOM을 만들다가 script 태그를 만나면 일시중지하고 src 속성에 정의된 파일을 서버에 요청하여 로드한 자바스크립트 파일이나 script 태그 내 자바스크립트 코드를 파싱하기 위해 자바스크립트 엔진에게 제어권을 넘긴다.
자바스크립트 파싱과 실행이 종료되면 렌더링 엔진으로 다시 제어권을 넘기고, 일시중지되었던 html 파싱을 다시 시작하여 DOM 생성을 진행한다.
자바스크립트 엔진
자바스크립트 엔진은 자바스크립트 코드를 파싱하여 CPU가 이해할 수 있는 저수준 언어로 변환하고 실행한다.
렌더링 엔진으로부터 제어권을 넘겨받으면 자바스크립트 코드를 파싱하며 AST(추상적 구문트리)를 생성한다. AST를 기반으로 한 인터프리터가 실행할 수 있는 중간코드인 바이트 코드를 생성하여 실행한다.
단순한 문자열인 자바스크립트 소스코드를 어휘분석하여 문법적 의미를 갖는 코드의 최소 단위인 토큰으로 분해한다.( 토그나이징)
토큰들의 집합을 구문분석하여 AST(추상적 구문트리)를 생성한다. AST는 인터프리터가 실행할 수 있는 중간 코드인 바이트 코드롤 변환되고 인터프리터에 의해 실행된다.
모든 자바스크립트 엔진은 ECMAScript 사양을 준수하며, V8(google chrome, node.js), SpiderMonkey(firefox), JavascriptCore(safari) 등이 있다.
리플로우와 리페인트
DOM API가 사용되어 DOM이나 CSSOM이 변경되면 다시 렌더트리로 결합되고 변경된 렌더트리를 기반으로 레이아웃과 페인팅 과정을 거쳐 다시 브라우저 화면에 렌더링하는 과정을 리플로우, 리페인트라고 한다.
리플로우는 레이아웃 계산을 다시 하는 것을 말하고, 노드 추가/삭제, 요소 크기/위치 변경, 윈도우 리사이징 등 레이아웃에 영향을 주는 변경이 발생한 경우에 한해 실행된다. 리페인트는 재결합된 렌더트리를 기반으로 다시 페인트 하는 것을 말한다.
레이아웃에 영향이 없는 변경은 리플로우 없이 리페인트만 실행된다.
'프로그래밍 > Javascript' 카테고리의 다른 글
[JS] 변수: var, let, const (0) | 2024.05.28 |
---|---|
[Javascript] 함수 선언, 함수 표현, 객체의 메서드 (0) | 2024.04.17 |
[Javascript] Function() 생성자, 화살표 함수 (0) | 2024.04.17 |
[Javascript] 비동기 처리: Promise객체, fetch, async / await (0) | 2024.04.09 |