728x90
0. 브라우저의 렌더링 과정
- 웹 애플리케이션의 클라이언트 사이드 자바스크립트는 브라우저에서 HTML, CSS와 함께 실행
- => 브라우저 환경을 고려할 때 더 효율적인 클라이언트 사이드 자바스크립트 프로그래밍 가능
- 파싱(구문 분석)
- 파싱(구문 분석) : 프로그래밍 언어의 문법에 맞게 작성된 텍스트 문서를 읽어 들여 실행하기 위해 텍스트 문서의 문자열을 토큰으로 분해하고 토큰에 문법적 의미와 구조를 반영하여 트리 구조의 자료구조인 파스 트리를 생성하는 일련의 과정
- 일반적으로 파싱이 완료된 이후에는 파스 트리를 기반으로 중간 언어인 바이트코드를 생성하고 실행
- 렌더링
- 렌더링 : HTML, CSS, 자바스크립트로 작성된 문서를 파싱하여 브라우저에 시각적으로 출력하는 것
브라우저의 렌더링 과정
- 브라우저는 HTML, CSS, 자바스크립트, 이미지, 폰트 파일 등 렌더링에 필요한 리소스를 요청하고 서버로부터 응답을 받은
- 브라우저의 렌더링 엔진은 서버로부터 응답된 HTML, CSS 파싱하여 DOM, CSSOM 생성하고 결합하여 렌더트리 생성
- 브라우저의 자바스크립트 엔진은 서버로부터 응답된 자바스크립트를 파싱하여 AST(abstract syntax tree) 생성하고 바이트 코드로 변환해 실행함
- 이때 자바스크립트는 DOM API를 통해 DOM, CSSOM 변경 가능
- 변경된 DOM과 CSSOM은 다시 렌더트리로 결합
- 렌더 트리를 기반으로 HTML 요소의 레이아웃(위치와 크기) 계산하고 브라우저 화면에 HTML 요소 페인팅
1. 요청과 응답
- 브라우저의 핵심 기능
- 브라우저의 핵심 기능 : 필요한 리소스(HTML, CSS, 자바스크립트, 이미지, 폰트 등의 정적 파일 또는 서버가 동적으로 생성한 데이터)를 서버에 요청하고 서버로부터 응답을 받아 브라우저에 시각적으로 렌더링 하는 것
- 렌더링에 필요한 리소스는 모두 서버에 존재하므로 필요한 리소스를 서버에 요청하고 서버가 응답한 리소스를 파싱하여 렌더링 하는 것
- 서버에 요청을 전송하기 위해 브라우저는 주소창 제공
- 브라우저 주소창에 URL을 입력하고 엔터 키 클릭 시 URL의 호스트 이릅이 DNS를 통해 IP 주소로 변환되고 이 IP 주소를 갖는 서버에게 요청을 전송함
- 브라우저의 주소창에 https://www.google.com/ 입력하고 엔터 키를 누르면
- 루트 요청(스킴(/)과 호스트만으로 구성된 URI에 의한 요청)이 구글 서버로 전송
- 루트 요청에는 명확히 리소스를 요청하는 내용이 없지만 일반적으로 서버는 루트 요청에 대해 암묵적으로 index.html을 응답함
- https://www.google.com/ === https://www.google.com/index.html
- 만약 index.html이 아닌 다른 정적 파일을 서버에 요청하려면 브라우저의 주소창에 요청할 정적 파일의 경로와 파일이름을 URI의 호스트 뒤의 패스에 기술하여 서버에 요청
- 루트 요청(스킴(/)과 호스트만으로 구성된 URI에 의한 요청)이 구글 서버로 전송
- 자바스크립트를 통해 동적으로 서버에 정적/동적 데이터를 요청 가능
- 요청과 응답은 개발자 도구의 Network 패널에서 확인 가능
- 브라우저의 렌더링 엔진이 HTML 을 파싱하는 도중에 외부 리소스를 로드하는 태그(link, img, script 등)을 만나면 HTML 파싱을 일시중단하고 해당 리소스 파일을 서버로 요청하기 때문
2. HTTP 1.1과 HTTP 2.0
HTTP
- HTTP : 웹에서 브라우저와 서버가 통신하기 위한 프로토콜
- 1989년 HTML, URL과 함께 팀 버너스 리 경이 고안
- 1991년 최초 문서화 이후 1996년 1.0, 1999년 1.1, 2015년 2 버전 발표
HTTP/1.1
- 커넥션 당 하나의 요청과 응답만 처리
- HTML 문서 내에 포함된 여러개의 리소스 요청(link, img, script 등)에 의한 리소스 요청, 응답이 개별적으로 전송
- 리소스의 동시 전송이 불가능한 구조 => 요청할 리소스의 개수에 비례해 응답 시간도 증가
HTTP/2
- HTTP/2 는 커넥션 당 여러개의 요청과 응답 가능
- 여러 리소스의 동시 전송이 가능해 페이지 로드 속도가 50% 정도 빠름
3. HTML 파싱과 DOM 생성
- 브라우저 요청에 의해 서버가 응답한 HTML 문서는 문자여롤 이루어진 순수한 텍스트
- 순수한 텍스트인 HTML 문서를 브라우저에 시각적인 픽셀로 렌더링하려면 HTML 문서를 브라우저가 이해할 수 있는 자료구조(객체)로 변환해 메모리에 저장해야됨
HTML 문서 파싱해 브라우저가 이해할 수 있는 자료구조인 DOM 생성
- 서버에 존재하던 HTML 파일이 브라우저의 요청에 의해 응답
- 서버는 브라우저가 요청한 HTML 파일을 읽어 들여 메모리에 저장한 다음 메모리에 저장된 바이트(2진수)를 인터넷을 경유해 응답
- 브라우저는 서버가 응답한 HTML 문서를 바이트(2진수) 형태로 응답
- 응답된 바이트 형태의 HTML 문서는 meta 태그의 charset 어트리뷰트에 의해 지정된 인코딩 방식을 기준으로 문자열 변환
- meta 태그의 charset 어트리뷰트에 선언된 인코딩 방식은 content-type : text/html; charset=utf-8 과 같이 응답 헤더에 담겨 응답
- 브라우저는 이를 확인하고 문자열로 변환
- 문자열로 변환된 HTML 문서를 읽어 들여 문법적 의미를 갖는 코드의 최소 단위인 토큰들로 분해
- 각 토큰들을 객체로 변환해 노드 생성
- 토큰 내용에 따라 문서 노드, 요소 노드, 어트리뷰트 노드, 텍스트 노드 생성
- 노드는 이후 DOM을 구성하는 기본 요소
- HTML 문서는 HTML 요소들의 집합으로 이루어지며 HTML 요소는 중첩 관계를 가짐
- HTML 요소의 콘텐츠 영역(시작 태그와 종료 태그 사이)에는 텍스트뿐만 아니라 다른 HTML 요소도 포함 가능
- HTML 요소 간에는 중첩 관계에 의해 부자 관계 형성
- HTML 요소간의 부자관계를 반영해 모든 노드들을 트리 자료구조로 구성
- 이 노드들로 구성된 트리 자료구조 = DOM =HTML 문서를 파싱한 결과물
4. CSS 파싱과 CSSOM 생성
- 렌더링 엔진은 HTML을 처음부터 한줄씩 순차적으로 파싱해 DOM 생성
- 렌더링 엔진은 DOM을 생성해 나가다가 CSS를 로드하는 link 태그나 style 태그를 만나면 DOM 생성을 일시중단
- link 태그의 href 어트리뷰트 지정된 CSS 파일을 서버에 요청하여 로드한 CSS 파일이나 style 태그 내의 CSS를 HTML과 동일한 파싱 과정(바이트 -> 문자 -> 토근 -> 노드 -> CSSOM)을 거치며 해석하여 CSSOM을 생성
- CSSOM은 CSS 상속을 반영해 생성
- CSS 파싱이 완료되면 HTML 파싱이 중단된 지점부터 다시 HTML을 파싱하기 시작해 DOM 생성 재개
5. 렌더 트리 생성
- 렌더링 엔진은 서버로부터 응답된 HTML과 CSS 파싱하여 각각 DOM과 CSSOM 생성
- DOM과 CSSOM은 렌더링을 위해 렌더 트리로 결합
- 렌더 트리는 렌더링을 위한 트리구조의 자료구조
- 화면에 브라우저 화면에 렌더링되지 않는 노드 (meta, script 태그 등)와 CSS에 의해 비표시(display:none) 되는 노드들은 불포함
- 이후 완성된 렌더 트리는 각 HTML 요소의 레이아웃(위치와 크기)을 계산하는데 사용되며 브라우저 화면에 픽셀을 렌더링하는 페인팅 처리에 입력
- 레이아웃 계산과 페인팅을 다시 실행하는 리렌더링은 비용이 많이 들고 성능에 악영향
- 레이아웃 계산과 페인팅 재차 실행되는 경우
- 자바스크립트에 의한 노드 추가 또는 삭제
- 브라우저 창의 리사이징에 의한 뷰포트 크기 변경
- HTML 요소의 레이아웃(위치, 크기)에 변경을 발생시키는 width/height, margin, padding, border, display, position, top/left/right/bottom 등의 스타일 변경
6. 자바스크립트 파싱과 실행
- HTML 문서 파싱한 결과물로서 생성된 DOM은 HTML 문서의 구조와 정보뿐만 아니라 HTML 요소와 스타일 등을 변경할 수 잇는 프로그래밍 인터페이스로서 DOM API 제공
- 자바스크립트 코드에서 DOM API 사용 시 이미 생성된 DOM을 동적으로 조작 가능
- 렌더링 엔진은 HTML 한줄씩 순차적으로 파싱하며 DOM을 생성해 나가다가 자바스크립트 파일을 로드하는 script 태그나 자바스크립트 코드를 콘텐츠로 담은 script 태그를 만나면 DOM 생성 일시 중단
- script 태그의 src 어트리뷰트에 정의된 자바스크립트 파일을 서버에 요청해 로드한 자바스크립트 파일이나 script 태그 내의 자바스크립트 코드를 파싱하기 위해 자바스크립트 엔진에 제어권을 넘김
- 이후 자바스크립트 파싱과 실행이 종료되면 렌더링 엔진으로 다시 제어권을 넘겨 HTML 파싱이 중단된 지점부터 다시 HTML 파싱 시작해 DOM 생성 재개
- 자바스크립트 파싱과 실행은 자바스크립트 엔진이 처리
- 자바스크립트 엔진은 자바스크립트 코드를 파싱해 CPU가 이해할 수 있는 저수준 언어로 변환하고 실행하는 역할
- 자바스크립트 엔진은 구글 크롬, Node.js의 V8 등 다양한 종류가 있고 ECMAScrtipt 사양 준수
- 렌더링 엔진으로부터 제어권 넘겨받은 자바스크립트 엔진은 자바스크립트 코드 파싱 시작
- 렌더링 엔진이 HTML과 CSS 파싱해 DOM과 CSSOM 생성하듯이 자바스크립트 엔진은 자바스크립트 해석해 AST(추상적 구문 트리) 생성
- AST 기반으로 인터프리터가 실행할 수 있는 중간 코드인 바이트 코드 생성해 실행
토크나이징
- 토크나이징 : 단순한 문자열인 자바스크립트 소스코드를 어휘 분석해 문법적 의미를 갖는 코드의 최소단위인 토큰들로 분해하는 과정
- 렉싱이라고도 부르지만 토크나이징과 미묘한 차이 있음
파싱
- 파싱 : 토큰들의 집합을 구문 분석해 AST 생성
- AST는 토큰에 문법적 의미와 구조를 반영한 트리구조의 자료구조
- AST는 인터프리터나 컴파일러만이 사용하는 것은 아님
- AST를 사용하면 TypeScript, Babel, Prettier 같은 트랜스파일러 구현 가능
- AST Explorer 웹사이트 방문 시 다양한 오픈소스 자바스크립트 파서 사용해 AST 생성 가능
바이트코드 생성과 실행
- 파싱의 결과물로서 생성된 AST는 인터프리터가 실행할 수 있는 중간 코드인 바이트 코드로 변환되고 인터프리터에 의해 실행
- V8 엔진의 경우 자주 사용되는 코드는 터보팬이라 불리는 컴파일러에 의해 최적화된 머신코드로 컴파일되어 성능 최적화
- 만약 코드의 사용 빈도가 적어지면 다시 디옵티마이징 하기도 함
7. 리플로우와 리페인트
- 자바스크립트 코드에 DOM, CSSOM 변경하는 DOM API가 사용된 경우 DOM 이나 CSSOM 변경
- 이때 변경된 DOM과 CSSOM은 다시 렌더 트리로 결합되고 변경된 렌더 트리를 기반으로 레이아웃과 페인트 과정을 거쳐 브라우저의 화면에 다시 렌더링 => 리플로우, 리페인트
- 리플로우와 리페인트가 반드시 순차적으로 동시에 실행되는 것은 아님
- 레이아웃에 영향이 없는 변경은 리플로우 없이 리페인트만 실행
리플로우
- 리플로우 : 레이아웃 계산을 다시 하는것
- 노드 추가/삭제, 요소의 크기/위치 변경
- 윈도우 리사이징 등 레이아웃에 영향을 주는 변경이 발생한 경우
리페인트
- 리페인트 : 재결합된 렌더 트리를 기반으로 다시 페인트
8. 자바스크립트 파싱에 의한 HTML 파싱 중단
- 브라우저는 동기적으로 HTML, CSS, 자바스크립트를 파싱하고 실행
- => script 태그의 위치에 따라 HTML 파싱이 블로킹되어 DOM 생성 지연될 수 있음
- 만약 head 태그 안, body 태그 최상단에 script 태그가 있는 경우
- 자바스크립트 파싱, 실행 이전까지 DOM 생성이 일시 중단되어 원하는 요소가 포함되지 않았을 수 있음
- 이때 자바스크립트 코드 안에서 DOM, CSSOM 변경하는 DOM API 사용할 경우 DOM, CSSOM이 이미 생성되어있어야함
- 이런 문제 회피하기 위해 body 요소 가장 아래에 자바스크립트 위치 시켜야함
- DOM 완성되지 않은 상태에서 자바스크립트가 DOM 조작 시 에러 발생
- 자바스크립트 로딩/파싱/실행으로 인해 HTML 요소들의 렌더링에 지정받는 일이 발생하지 않아 페이지 로딩 시간 단축
9. script 태그의 async/defer 어트리뷰트
- 자바스크립트 파싱에 의한 DOM 생성이 중단되는 문제를 근본적으로 해결하기 위해 HTML5부터 script 태그에 async와 defer 어트리뷰트 추가
- async와 defer 어트리뷰트는 src 어트리뷰트를 통해 외부 자바스크립트 파일을 로드하는 경우에만 사용 가능
- src 어트리뷰트가 없는 인라인 자바스크립트에는 사용 불가능
- async와 defer 어트리뷰트 사용 시 HTML 파싱과 외부 자바스크립트 파일의 로드가 비동기적으로 동시에 진행
- 하지만 async와 defer 는 자바스크립트의 실행 시점에 차이가 있음
async 어트리뷰트
- HTML 파싱과 외부 자바스크립트 파일의 로드가 비동기적으로 동시에 진행
- 자바스크립트 파싱과 실행은 자바스크립트 파일의 로드가 완료된 직후 진행되며 이때 HTML 파싱 중단
- 여러개의 script 태그에 async 어트리뷰트를 지정하면 script 태그의 순서와는 상관없이 로드가 완료된 자바스크립트부터 먼저 실행되므로 순서가 보장되지 않음 => 순서 보장 필요한 경우 사용 금지
- IE10 이상에서 지원
defer 어트리뷰트
- HTML 파싱과 외부 자바스크립트 파일의 로드가 비동기적으로 동시에 진행
- 자바스크립트 파싱과 실행은 HTML 파싱이 완료된 직후, DOM 생성 완료된 직후 (DOMContentLoaded 이벤트 발생) 진행
- DOM 생성 완료 이후 실행되어야할 자바스크립트에 유용
- IE10 이상에서 지원
모던 자바스크립트 딥다이브를 정리한 내용입니다!!
728x90
'개념 정리 > 모던 자바스크립트 딥다이브' 카테고리의 다른 글
모던 자바스크립트 : 비동기 프로그래밍 (0) | 2023.12.06 |
---|---|
모던 자바스크립트 : DOM (1) | 2023.12.06 |
모던 자바스크립트 : Set과 Map (0) | 2023.11.30 |
모던 자바스크립트 : 디스트럭처링 할당 (1) | 2023.11.30 |
모던 자바스크립트 : 스프레드 문법 (0) | 2023.11.30 |