화면에 UI를 띄우기 위해 브라우저는 열심히 일을 한다.
URL을 입력하고 특정 사이트에 접속하는 순간까지 네트워크 계층에서 많은 일들을 처리한 후, 서버로 부터 보여줄 데이터를 받기 위해 요청을 보내는 것에서 시작한다.
브라우저는 서버로 요청(Request)을 보내고,
서버로 부터 응답(Response)을 받는다.
이 응답 메시지를 브라우저에 표시하는 것인데 HTML, CSS, JavaScript, 이미지 파일 등을 받게 된다. 실제로 HTML파일의 경우 네트워크 응답메시지의 Response에서 HTML태그를 볼 수 있다.
이 HTML파일을 받아오면 브라우저는 어떻게 이 태그를 인식하고 화면에 그림을 그릴까? 우선, 이 일을 하는 주체는 렌더러 프로세스이다. 렌더러 프로세스의 역할은 웹 콘텐츠(HTML, CSS, JavaScript)를 사용자와 상호작용할 수 있는 웹 페이지로 변환하는 것이다.
브라우저는 문자열 HTML정보를 파싱하여 DOM (Document Object Model)이라는 객체형태의 모델로 저장한다. tree형태로 저장되어 DOM Tree라고 한다.
우리는 HTML파일에서 <script>
태그로 JS파일을 요청하고, <link>
태그로 CSS파일을 불러오도록 작성한다. 이것을 HTML파서가 생성된 토큰을 확인하고 브라우저의 네트워크 스레드에 콘텐츠를 받아오도록 요청을 보낸다.
이 때 주의해야할 점이 있다. <script>
태그는 HTML파싱 작업을 중단시키고 JS파일을 분석하는 일을 우선적으로 하게 한다. 이유는 JS가 DOM을 동적으로 조작할 수 있기 때문에 분석을 완료한 다음 다시 HTML파싱 작업을 진행한다.
때문에 만일, JS파일 로딩이 오래걸리는 작업이라면, 이 JS파일을 다 로딩하기 전까지 우리는 빈 하얀 화면, 또는 로딩이 중간에 멈춰진 화면을 장시간 노출하게 된다. 또한 DOM이 완료되지 않은 상태에서 JS파일이 DOM에 접근해 조작하려한다면 해당 요소를 찾을 수 없다는 에러를 발생시키기도 한다.
이러한 이유로 HTML파일을 모두 파싱한 후의 시점인 <body>
태그 내부 가장 마지막 라인에 <script>
태그를 걸어야 한다.
(특히 AJAX로 인해 과거보다 로딩해야할 JS파일의 크기가 매우 커졌기 때문에 반드시 이 점을 확인할 필요가 있다.)
또는, <script>
태그에 async, defer 속성을 추가하여 비동기적으로 파일을 로딩하며 HTML파일 파싱을 동시에 진행할 수 있게 할 수 있다. 또는 빠르게 보여져야 하는 콘텐츠는 <link rel='preload'>
와 같이 우선적으로 로딩하도록 지시할 수도 있다.
css파싱 후 확정된 스타일(Computed Style)을 각 돔 노드에 인식 시킨다. DOM Tree에 스타일을 반영한 결과를 CSSOM이라고 말한다.
이 스타일을 계산하는 작업은 상당히 비용이 큰 작업이라는 것을 미리 알아두고 가자.
렌더링 트리는 화면에 표시되는 모든 노드의 콘텐츠 및 스타일 정보를 모두 포함하고 있다.
HTML DOM트리의 구조와 해당 노드들의 각각의 스타일을 파악했으면
브라우저의 어느 쪽에 배치할지 판단하는 레이아웃 작업이 남아있다.
이 작업으로 만들어진 결과를 레이아웃 트리라고 말한다.
레이아웃 트리는 X,Y좌표, 박스 크기와 같은 정보, 의사클래스(psedudo class_ex) div::after{content:''}
)와 같은 속성이 포함되어 있다.
painting : 레이아웃 트리를 순회하면서 어떤 순서로 그림을 그릴지 기록을 작성한다. z-index나 canvas를 떠올리면 이해하기 쉽다.
draw : 페인트기록을 기반으로 실제 브라우저에 비트맵,텍스처를 만들어 내는 과정을 말한다. 픽단위로 변환하는 작업을 래스터화(resterizing)라고 한다.
(*최신 브라우저는 합성_compositing이 사용되고 있다. 웹페이지의 각 부분을 분리하여 별도로 래스터화하고 변경이 필요한 부분만 합성하여 보여주는 기술이다. Layout과 Paint가 다시 발생될 필요가 없어 성능상 이점을 갖는다. 쉽게 이해하자면 애니메이션에서 배경은 그대로 있고, 움직이는 주체만 새로 합성된 것을 생각해보자)
여기까지 브라우저에 화면이 생성되는 과정을 대략적으로 훑어봤다.
간단하게 정리해보면 아래와 같다.
HTML파싱을 통해 DOM생성 - CSS파싱으로 CSSOM 생성 - 이 둘을 합쳐 RenderTree 생성 - 레이아웃 트리 생성 - 페인팅기록 생성 및 드로잉(합성)
화면을 렌더링 하기까지 꽤 많은 과정을 거쳤고, 이는 많은 비용을 요구하는 작업들이다. DOM변경이 필요할 때마다 파싱부터 새로 작업을 하기 때문에 변경요소를 제외하고 동일한 작업을 반복하는 것은 비효율적이며 페이지 규모가 커질 수록 렌더링의 부담이 커지게 된다. 이 점 때문에 Virtual DOM의 장점이 빛을 발하는 듯하다
(관련 내용은 기존 포스팅을 참고하면 도움이 될듯하다.👉링크)