브라우저의 동작 원리

이효범·2022년 4월 13일
0

DOM

목록 보기
2/2

목차

  1. 브라우저란?
  2. 브라우저의 주요 기능
  3. 브라우저의 기본 구조
  4. 렌더링 엔진
  5. 정리

브라우저란?

브라우저는 웹 페이지 이미지, 비디오 등의 콘텐츠를 수신, 전송 및 표현하는 소프트웨어이다.

브라우저의 주요 기능

브라우저는 사용자가 선택한(요청한) 리소스를 웹 서버에 요청하고, 브라우저 창에 표시함으로써 사용자에게 제공한다.

  1. 우리가 url을 통해 웹 사이트에 접속하게 되면, 해당 사이트의 리소스들을 브라우저가 웹 서버에 요청한다.
  2. 서버는 해당 웹 사이트의 HTML, CSS 등의 리소스들을 브라우저에게 응답으로 전송한다.
  3. 브라우저는 해당 문서들을 파싱한 후 사용자에게 제공한다.

브라우저의 기본 구조

브라우저는 크게 7개의 구조로 나눌 수 있다. 해당 구조들은 별도의 프로세스에서 실행된다.

  1. 사용자 인터페이스
    • 주소 표시줄, 이전 다음버튼, 북마크 기능 등 요청한 페이지가 렌더링되는 창을 제외한 브라우저의 모든 부분을 말한다.
  2. 브라우저 엔진
    • 브라우저 엔진은 사용자 인터페이스와 렌더링 엔진 사이의 동작을 제어하는 핵심 중추 부분이다. 데이터 저장공간을 참조하여 로컬에 데이터를 쓰고 읽으며 다양한 작업을 수행한다.
  3. 렌더링 엔진
    • 렌더링 엔진은 요청한 리소스를 파싱하여 출력하는 기능을 담당한다.
  4. 통신
    • 통신(= 네트워크 레이어)은 HTTP 요청과 같은 네트워크 호출을 담당한다.
  5. JS 엔진
    • JS 엔진은 자바스크립트 언어를 파싱하고 실행한다.
  6. UI 백엔드
    • UI 백엔드는 렌더링 엔진에서 생성된 RenderTree를 브라우저에 그리는 인터페이스이다.
  7. 데이터 저장 공간
    • 데이터 저장 공간은 LocalStorage, IndexedDB, WebSQL 등의 메모리를 활용하여 저장하는 영역이다.

이 중에서 렌더링 엔진에 대해서 좀 더 자세히 알아보자.

렌더링 엔진

렌더링 엔진은 사용자의 요청에 따른 서버의 응답 내용인 HTML, CSS 등의 리소스들을 파싱하여 브라우저에 표시한다.

브라우저마다 각각 다른 렌더링 엔진을 사용하는데, 크롬은 블링크, 사파리는 웹킷, 파이어폭스는 게코, 인터넷 익스플로러는 트라이던트를 사용한다.
즉 각 브라우저는 서로 다른 데이터 해석 방식을 갖고 있으며 특정 웹 사이트의 외관 또는 기능이 브라우저마다 다르게 표시될 수 있습니다.

따라서 개발자는 브라우저간의 지속성을 유지하기위해 웹 표준을 고려하여 개발해야한다.

그렇다면 렌더링 엔진은 어떻게 동작할까?
렌더링 엔진마다 약간의 용어 차이가 있지만, Webkit을 기준으로 알아본다.

  1. 먼저 서버의 응답 내용중 HTML파일을 파싱 후 돔트리를 구축한다.
    또한 CSS파일 및 style요소 모두에서 스타일 데이터 파싱 후 CSSOM (CSS object model)Tree를 구축한다.

  2. 그 후 완성된 돔 트리들을 Attachment 작업을 거친다. 이는 HTML 규칙에 맞게 스타일 정보를 사용하여 렌더 트리를 생성하는 과정이다. 게코 엔진에서는 콘텐츠 싱크 레이어를 거친다고 말한다.

  3. 다음으로 각 노드가 화면에 어느곳에 어느 크기로 배치되어야 하는지 정확한 좌표를 제공받아 해당 좌표에 노드들을 배치하는 레이아웃 프로세스를 거친다.
    이는 게코 엔진에서는 리플로우 과정이라 한다.

  4. 마지막으로 UI 백엔드 레이어를 사용하여 화면에 그리는 페인트 작업을 거쳐 최종적으로 화면에 요소들을 그린다.

이러한 문서 파싱과 배치 작업은 비동기적으로 동작한다. 네트워크로부터 나머지 내용이 전송되길 기다리는 동시에, 받은 내용의 일부를 먼저 화면에 표시하는 것이다. 따라서 사용자는 모든 요소가 그려지기 이전에 일부의 요소들을 먼저 확인할 수 있다.

그렇다면 렌더링 엔진이 HTML, CSS를 파싱한다는 것은 무엇일까?
파싱이란 브라우저가 코드를 이해하고 사용할 수 있는 구조로 변환하는 것이다.

파싱의 결과물은 노드 트리로 생성된다. HTML 파일을 파싱하면 돔 트리가 생성되고 CSS 파일을 파싱하면 CSSOM 트리가 생성된다.

만약 HTML 파일을 파싱하던 중 script 요소를 발견한다면 어떻게 될까?
HTML 파서는 HTML 파일을 읽어 내려가던 중 script요소를 만나면 DOM 생성 즉 파싱을 중지한다. 그 후 JS 엔진에 작업 권한을 넘긴다. JS 엔진은 JS 파일을 파싱하고 실행한 후 작업이 완료되면 다시 HTML 파서에게 작업 권한을 넘긴다.

그러고 나면 HTML 파서는 중지되었던 시점부터 다시 돔 생성 작업을 계속하게 된다.

해당 과정에서 확인할 수 있듯이 브라우저는 동기적으로 HTML, CSS, JS를 처리한다. 따라서 자바스크립트 엔진에 제어 권한이 있을 때 해당 코드가 완성되지 않은 DOM을 조작하게 된다면 에러가 발생한다.

따라서 일반적으로 body의 끝부분에 script를 넣어주는 것이 좋은 것이다.
하지만 상황에 따라 script를 body 끝부분에 놓을 수 없을 때 활용할 수 있는 방법들도 있다.

먼저 스크립트 태그의 async 와 defer 속성을 사용할 수 있다.

async를 사용하면 script 태그를 만나도 파싱이 중단되지 않는다.
script 로드와 HTML 파싱이 함께 이루어지다가, 로드가 완료된 시점 즉 실행되는 시점에만 HTML 파싱이 잠시 중단되고, 실행이 완료되면 파싱이 재개되게 된다.

defer 속성은 async와 동일하게 script 로드와 HTML 파싱이 함께 이루어진다. 단 HTML 파싱이 완료된 후에 script를 실행시키게 된다.

스크립트 내부에서도 로딩 순서를 제어할 수 있다. DOMContentLoaded 내부의 코드는 DOM 생성이 끝난 후 실행다.

load 내부 코드는 HTML로 돔 트리를 만드는 작업이 완료되었을 뿐만 아니라, 이미지나 style 시트 같은 외부 자원도 모두 불러온 후 실행된다. 즉 문서에 포함된 모든 콘텐츠들을 전부 로드한 후 실행한다.

이렇게 스크립트 로딩 순서를 제어함으로써, DOM 생성이 중단되거나 코드가 맞물리는 오류 등을 방지할 수 있다.

정리

최종적으로 브라우저의 렌더링 과정을 정리해보자.

  1. 사용자가 url을 통해 웹 리소스를 요청
  2. 서버에서 HTML, CSS 등의 다양한 리소스를 응답으로 제공합니다.
  3. 해당 리소스들을 파싱한 후 Attachment 작업을 거쳐 렌더 트리를 생성합니다(Attachment).
  4. 그 다음 렌더 트리의 노드들을 layout Process를 거쳐 배치하고
  5. 실제 화면에 출력하여 사용자에게 제공한다.
profile
I'm on Wave, I'm on the Vibe.

0개의 댓글