브라우저의 작동 원리

늘보·2021년 8월 13일
1

Web

목록 보기
4/6

자바스크립트와 브라우저

구글의 V8 자바스크립트 엔진으로 빌드된 자바스크립트 런타임 환경인 Node.js의 등장으로 자바스크립트는 웹 브라우저를 벗어나 서버 사이드 개발에서도 사용할 수 있는 범용 개발 언어가 되었다.

하지만 자바스크립트가 가장 많이 사용되는 분야는
여전히 웹 브라우저 환경에서 동작하는 웹페이지/애플리케이션의 클라이언트 사이드다.

대부분의 프로그래밍 언어는 운영체제(OS)나 가상 머신(Virtual Machine, VM) 위에서 실행되지만 웹 애플리케이션의 클라이언트 사이드 자바스크립트는 브라우저에서 HTML, CSS와 함께 실행된다.

그렇다면 브라우저는 HTML, CSS, 자바스크립트로 작성된 텍스트 문서를
어떻게 파싱(해석)하여 브라우저에 렌더링 하는 것일까?

브라우저의 기능

브라우저의 핵심 기능은 사용자가 참조하고 하는 웹페이지를 서버에 요청(Request)하고 서버의 응답(Response)를 받아 브라우저에 표시하는 것이다. 브라우저는 서버로부터 HTML, CSS, Javascript, 이미지 파일 등을 응답받는다. HTML, CSS 파일은 렌더링 엔진의 HTML 파서와 CSS 파서에 의해 파싱(Parsing)되어 DOM, CSSOM 트리로 변환되고 렌더 트리로 결합된다. 이렇게 생성된 렌더 트리를 기반으로 브라우저는 웹페이지를 표시한다.

자바스크립트는 렌더링 엔진이 아닌 자바스크립트 엔진이 처리한다. HTML 파서는 script 태그를 만나면 자바스크립트 코드를 실행하기 위해 DOM 생성 프로세스를 중지하고 자바스크립트 엔진으로 제어 권한을 넘긴다. 제어 권한을 넘겨 받은 자바스크립트 엔진은 script 태그 내의 자바스크립트 코드 또는 script 태그의 src 어트리뷰트에 정의된 자바스크립트 파일을 로드하고 파싱하여 실행한다. 자바스크립트의 실행이 완료되면 다시 HTML 파서로 제어 권한을 넘겨서 브라우저가 중지했던 시점부터 DOM 생성을 재개한다.

이처럼 브라우저는 동기(Synchronous)적으로 HTML, CSS, Javascript을 처리한다. 이것은 script 태그의 위치에 따라 블로킹이 발생하여 DOM의 생성이 지연될 수 있다는 것을 의미한다. 따라서 script 태그의 위치는 중요한 의미를 갖는다.

브라우저의 웹 페이지 렌더링 최적화

최근 일반적인 스크린은 1초에 화면을 60번 그린다. 이것은 60fps(frame per second)인 것인데, 이 때문에 브라우저 역시 60fps를 유지해야 웹페이지가 매끄럽게 보일 수 있다. 실제 기기의 스크린이 업데이트 되는 속도에 브라우저가 렌더링 되는 속도를 맞춰야 하기 때문이다. 만약 브라우저가 1초에 60프레임을 그리지 못한다면, 웹 페이지에서 스크롤을 내린다거나 드래그해서 뭔가를 움직일 때 버벅거리게 될 것이다.(이러한 현상을 Jank라고 함) 또는 페이지 자체가 뜨는 데까지 오랜 시간이 걸릴 수도 있다. 이럴 때 최적화(optimization)이 필요하다.

'브라우저 랜더링 성능 최적화'라는 말을 많이 들어봤을 것이다. 그렇다면 최적화를 어떻게 시켜야 하는것일까?

브라우저가 1초에 60프레임을 그릴 수 있으려면, 1개의 프레임을 그릴 때 약 16ms를 사용해야 한다. 그러니 렌더링 성능 최적화를 위해서는 먼저 브라우저가 그 페이지의 하나의 프레임을 어떻게, 얼마동안 그리는지 알아봐야 한다. 그리고 그 과정에서 시간이 오래 걸리는 단계를 좀 더 효율적으로 바꿔 최대한 한 프레임을 빠르게 그려낼 수 있도록 만들면, 성능 향상에 도움이 될 것이다.

브라우저가 하나의 화면을 그려내는 이 과정을 중요 랜더링 경로(Critical Rendering Path)라고 부른다. 우리가 일상적으로 접하는 주소창에 url을 입력하고, 엔터키를 치면 브라우저는 해당 서버에 요청(request)을 보내게 된다. 서버에서는 응답(response)으로 HTML 데이터를 내려주는데, 이 HTML 데이터를 실제 우리가 보는 화면으로 그리기까지 브라우저는 다음 단계를 거쳐 작업을 진행한다. 이 과정의 각 단계가 최대한 효율적으로 이루어지도록 만드는 것을 보통 최적화라고 부른다.

브라우저의 렌더링 과정 (상세)

앞에서도 계속 브라우저의 '렌더링' 이라고 말했는데, 그럼 '렌더링'의 정의는 무엇일까?

렌더링 이란 서버로부터 HTML 파일을 받아 브라우저에 뿌려주는 과정을 말한다.

이러한 렌더링 과정을 설명하면 다음과 같다.

  1. 웹 페이지 또는 어플리케이션에 대한 요청은 HTML 요청으로 시작된다.

  2. 서버는 응답 헤더 또는 데이터로 HTML을 반환한다.

  3. 브라우저는 HTML을 분석하고 수신된 bytes를 DOM 트리로 변환하기 시작한다.

  4. 브라우저는 스타일시트, 스크립트 또는 포함된 이미지 참조인 외부 자원에 대한 링크를 찾을때마다 요청을 시작합니다.

  5. 불러온 Assets를 다룰 때까지 나머지 HTML을 분석하는 작업하는 일부 요청은 중단되며 차단됩니다.

  6. 파싱은 CSS file을 만났을때도 계속되지만 특히 async 또는 defer 속성이 없는 <script> 태그를 만났을 경우에는 렌더링을 멈추고 HTML 파싱을 중단한다. 비록 브라우저의 프리로드(preload) 스캐너가 이 과정을 가속화하지만 과도한 스크립트는 여전히 심각한 병목현상이 될 수 있다.

  7. 메인 스레드가 HTML, CSS를 분석하는 동안 Preload scanner는 스크립트와 이미지를 검색할 것이고 다운로드 받기 시작할 것이다. 스크립트가 DOM 트리 구성 프로세스를 막지 않도록 보장하기 위해, 만약 Javascript 파싱 또는 실행 순서가 중요하지 않다면 async 또는 defer 속성을 추가해야 한다.

  8. CSS를 받기 위해 대기하는 것은 HTML 분석 또는 다운로딩은 막지 않지만 Javascript는 종종 HTML 요소에서 CSS 속성을 조회하는데 영향을 끼치기 때문에 막는다.

  9. 브라우저는 CSSOM 구축 작업이 끝날때까지 요청을 만들고 DOM을 생성하는 HTML을 계속해서 분석한다.

  10. DOM과 CSSOM이 완료되면 브라우저는 렌더 트리를 생성하고 보여지는 컨텐츠를 위해 스타일을 계산한다. (Layout)

  11. 레이아웃 은 너비, 높이 그리고 렌더 트리 안에서 모든 노드들의 위치를 결정하는 과정으로, 각 노드의 위치를 계산하기 위해 렌더 트리에서 레이아웃을 작동시키는 것이다. 페이지 안에서 각 오브젝트의 크기와 위치에 대한 결정도 추가됩니다. 리플로우 는 페이지의 특정 부분 또는 전체 document의 어떤 연속적인 크기와 위치에 대한 결정이다. 렌더트리가 완료된 후 모든 렌더 트리 요소들에 대한 위치와 크기가 정의된 레이아웃이 만들어집니다. 일단 완료되면 레이지는 렌더링되거나 또는 화면에 그려진다.

브라우저의 렌더링 과정(요약)

  1. HTML 마크업을 Parsing(처리)하여 DOM 트리를 빌드한다. (“무엇을” 그릴지 결정한다.) (DOM 파싱)

  2. CSS Parsing(처리)하여 CSSOM 트리를 빌드한다. (“어떻게” 그릴지 결정한다.) (CSS 파싱)

  3. DOM 및 CSSOM 을 결합하여 렌더링 트리를 형성한다. (“화면에 그려질 것만” 결정) (Combination)

  4. 렌더링 트리에서 레이아웃을 실행하여 각 노드의 기하학적 형태를 계산한다. (“Box-Model” 을 생성한다.) (Layout)

  5. 개별 노드를 화면에 페인트한다.(or 래스터화) (Painting)

  6. 렌더링이 완료된 상태에서 사용자의 인터랙션에 의해 화면의 일부 영역이 변경된다면, 리플로우 또는 리페인트가 발생한다.

참조 링크

Javascript Deep Dive(책) - 브라우저의 렌더링 과정(38)
https://m.post.naver.com/viewer/postView.nhn?volumeNo=8431285&memberNo=34176766
https://d2.naver.com/helloworld/59361 (브라우저 작동원리에 대한 상세한 글)

0개의 댓글