자바스크립트 셀프 QnA(2): 브라우저 렌더링

9rganizedChaos·2021년 10월 24일
0
post-thumbnail

(<자바스크립트 셀프 QnA> 시리즈에 작성된 포스팅들은 각 주제에 해당하는 <모던 자바스크립트 딥다이브> 챕터를 읽으며 요약한 내용입니다. 더 자세한 내용은 <모던 자바스크립트 딥다이브>를 참고해주세요.)

NodeJS의 등장으로 자바스크립트는 웹 브라우저를 벗어나 서버 사이드 애플리케이션 개발에서도 사용할 수 있는 범용 개발언어가 되었다. 그러나 여전히 자바스크립트가 가장 많이 사용되는 분야는 웹 브라우저 환경에서 동작하는 웹페이지/애플리케이션의 클라이언트 사이드! 이때 보통 자바스크립트는 HTML, CSS와 함께 실행된다. 때문에 브라우저 환경을 잘 이해할 수록 효율적인 클라이언트 사이드 자바스크립트 프로그래밍이 가능하다!

Q1 파싱과 렌더링은 무엇인가요?

  • 파싱: 프로그래밍 언어의 문법에 맞게 작성된 텍스트 문서를 읽어 들여 실행하기 위해 텍스트 문서의 문자열을 토큰으로 분해하고 토큰에 문법적 의미와 구조를 반영해 트리 구조의 자료구조인 파스 트리를 생성하는 일련의 과정
  • 렌더링: HTML, CSS, 자바스크립트로 작성된 문서를 파싱하여 브라우저에 시각적으로 출력하는 것

Q2 브라우저 렌더링 과정을 간단히 요약해주세요.

  • 1) 브라우저는 렌더링에 필요한 리소스를 요청하고 서버로부터 응답 받는다.
  • 2) 브라우저 렌더링 엔진은 HTML을 파싱해 DOM, CSS를 파싱해 CSSOM을 생성하고 이들을 결합해 렌더 트리를 생성한다.
  • 3) 자바스크립트를 파싱해 AST를 생성하고, 바이트 코드로 변환하여 실행한다. (이 때 자바스크립트는 DOM API를 통해 DOM이나 CSSOM을 변경할 수 있다. 변경된 것들은 다시 렌더트리로 결합된다.
  • 4) 렌더 트리를 기반으로 HTML 요소의 레이아웃을 계산하고 브라우저 화면서 HTML 요소를 페인팅한다.

Q3 브라우저의 요청과 응답

  • 브라우저의 주 역할은 리소스를 서버에 요청하고 응답을 받아와 브라우저에 렌더링 하는 것!
  • 서버에 요청을 전송하기 위해 브라우저에 주소창이 있다. 주소창에 url을 입력하면 url의 호스트 이름(도메인)이 DNS를 통해 IP 주소로 변환되고, 해당 IP 주소를 갖는 서버에게 요청 전송!
  • 특정한 정적 리소스를 지정하지 않으면 일반적으로 서버는 루트 요청에 대해 index.html을 응답하도록 설정되어 있다.
  • ajax나 RestAPI를 통해서도 서버에 정적 파일을 요청할 수 있다.

  • HTML 파싱 도중에 외부 리소스를 로드하는 태그, link img script 태그 등을 만나면 HTML 파싱이 중단되고 해당 리소스 파일을 서버로 요청해 받아온다!
  • 브라우저와 서버의 통신규약 HTTP! 다중 요청/응답이 불가한 HTTP1.1 대신 다중 요청/응답이 가능한 HTTP2.0을 사용하면 페이지 로드 속도가 약 50% 정도 빠르다.

Q4 HTML 파싱과 DOM 생성

  • 브라우저 요청에 서버가 응답한 HTML 문서는 문자열로 이루어진 순수한 텍스트.
  • 순수 텍스트를 렌더링하려면 브라우저가 이해할 수 있는 자료구조(객체)로 변환하여 메모리에 저장해야 한다.
  • 브라우저의 렌더링 엔진은 HTML 문서를 파싱해 브라우저가 이해할 수 있는 자료구조인 DOM(Document Object Model)을 생성한다.
  • DOM은 결국 HTML 문서를 파싱한 결과물이다.

  • 서버는 브라우저가 요청한 HTML 파일을 읽어 메모리에 저장하고, 메모리에 저장된 바이트를 응답한다.
  • 바이트 형태의 HTML 문서는 meta 태그의 charset 어트리뷰트에 의해 저장된 인코딩 방식을 기준으로 문자열로 변환된다.
  • 문자열로 변환된 HTML 문서를 일겅들여 문법적 의미를 갖는 코드의 최소단위인 토큰들로 분해한다.
  • 각 토큰들을 객체로 변환해 노드를 생성한다.
  • HTML 요소 간의 부자 관계를 반영해 모든 노트들을 트리 자료구조로 구성한다. 이렇게 구성된 트리 자료구조를 DOM이라고 한다.

Q5 CSS 파싱과 CSSOM 생성

  • HTML과 동일하게 바이트 > 문자 > 토큰 > 노드 > CSSOM 과정을 거쳐 생성된다.
  • CSSOM은 CSS의 상속을 반영하여 생성된다.

Q6 렌더트리 생성

  • 렌더링 엔진을 DOM과 CSSOM을 결합해 렌더 트리를 생성한다.
  • 렌더 트리는 렌더링을 위한 트리 구조의 자료구조! 렌더 트리는 HTML 요소의 레이아웃을 계산하는데 사용되며 브라우저 화면에 픽셀을 렌더링 하는 페인팅 처리에 입력된다.
  • 렌더 트리는 브라우저 화면에 렌더링 되는 노드 만으로 구성된다. (스크립트 태그나, display: none 같은 애들은 포함되지 않는다는 뜻!)

  • 그러므로 자바스크립트에 노드 추가/삭제, 뷰포트 변경, HTML 요소의 레이아웃에 변경을 발생시키는 스타일 변경은 리렌더링을 일으키고, 이는 성능에 악영향을 주기 쉽다.
  • 리렌더링이 빈번히 발생하지 않도록 프로그래밍을 하는 것이 중요하다.

Q7 자바스크립트 파싱과 실행

  • 자바스크립트 파싱과 실행은 브라우저의 렌더링 엔진이 아닌 자바스크립트 엔진이 처리한다.
  • 자바스크립트 엔진은 NodeJS의 V8, 파이어폭스의 SpiderMonkey, 사파리의 JavaScriptCore 등 다양한 종류가 있다. 모두 ECMAScript 사양을 준수한다.

Q8 리플로우와 리페인트

  • 자바스크립트 코드에서 DOM이나 CSSOM을 변경하는 DOM API가 사용된 경우 DOM이나 CSSOM이 변경되어, 리플로우와 리페인트가 일어난다.
  • 리플로우: 레이아웃 계산을 다시 함
  • 리페인트: 재결합된 렌더 트리를 기반으로 다시 페인트를 하는 것
  • 레이아웃에 변경이 없는 경우 리플로우 없이 리페인트만 실행된다.

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

  • 렌더링 엔진과 자바스크립트 엔진은 병렬적으로 파싱을 실행하지 않고, 직렬적으로 파싱을 수행한다.
  • 브라우저는 동기적으로 HTML, CSS, 자바스크립트를 파싱하고 실행한다. script 태그의 위치에 따라 HTML 파싱이 블로킹되어 DOM 생성이 지연될 수 있다.
  • 자바스크립트 코드에서 DOM이나 CSSOM을 변경하는 DOM API를 활용할 경우, 해당 DOM이나 CSSOM이 이미지 생성되어 있어야 한다.
  • 그래서 보통 body의 가장 하단에 스크립트 태그를 위치시킨다.
  • DOM이 완성되지 않은 상태에서 DOM을 조작해 에러를 발생시키는 상황을 피함과 동시에 자바스크립트의 로딩/파싱/실행으로 인해 HTML 요소들의 렌더링에 지장 받는 일이 발생하지 않아 페이지 로딩 시간이 단축된다.

Q10 script 태그의 async/defer 어트리뷰트

  • 위 DOM 생성 중단 문제를 해결하기 위해 HTML5 부터 script 태그에 async와 defer 속성이 추가되었다.
  • HTML 파싱과 외부 자바스크립트 파일의 로드가 비동기적으로 동시에 진행된다.
<script async src="extern.js"></script>
<script defer src="extern.js"></script>
  • async: HTML 파싱과 외부 자바스크립트 파일의 로드가 비동기적으로 동시에 진행된다. 하지만 자바스크립트 파일이 로드되면 바로 자바스크립트 파싱과 실행이 진행되며 이때 HTML 파싱은 중단된다.
  • defer: 위와 동일하게 외부 자바스크립트 파일의 로드가 비동기적으로 동시에 진행된다. 하지만 자바스크립트의 파싱과 실행은 HTML 파싱이 완료된 직후에 진행된다.
profile
부정확한 정보나 잘못된 정보는 댓글로 알려주시면 빠르게 수정토록 하겠습니다, 감사합니다!

0개의 댓글