브라우저의 주요 기능
- 사용자가 선택한 자원(HTML, PDF, Image 등)을 서버에 요청하고 브라우저에 표시하는 것을 말함
- 브라우저는 HTML, CSS에 따라 HTML을 해석하고 표시
브라우저의 기본 구조
1. 사용자 인터페이스
- 요청한 페이지를 보여주는 창을 제외한 나머지 모든 부분
2. 브라우저 엔진
- 사용자 인터페이스와 렌더링 엔진 사이의 동작을 제어
3. 렌더링 엔진
- 요청한 콘텐츠를 표시, HTML 요청시 HTML과 css 파싱해서 표시
4. 통신
- http 요청과 같은 네트워크 호출에 사용
5. UI 백엔드
- 콤보 박스와 창 같은 기본적인 장치를 그린다. os 사용자 인터페이스 체계 사용
6. 자바스크립트 해석기
7. 자료 저장소
- 자료 저장, 쿠키를 저장하는 것과 같이 하드디스크 저장
렌더링 엔진
- 요청 받은 내용을 브라우저 화면에 표시한다.
동작 과정
- 렌더링 엔진은 통신으로부터 요청한 문서의 내용을 얻는 것으로 시작하는데 문서의 내용은 보통 8KB 단위로 전송한다.
- 렌더링 엔진은 HTML 문서를 파싱하고 "콘텐츠 트리" 내부에서 태그를 DOM 노드로 변환한다.
<html>
<body>
<p>
Hello World
</p>
<div> <img src = "example.png"/></div>
</body>
</html>
- 위 코드를 DOM Tree로 변환하면 다음과 같다.
- 이후 외부 CSS 파일과 함께 스타일 요소도 파싱한다.
- 이 스타일 정보와 HTML 표시는 "렌더 트리"라는 또 다른 트리를 생성한다.
- 렌더 트리는 보이는 emlement들로 구성되며, 색상 또는 면적과 같은 시각적 속성이 있는 사각형을 포함하고 있고, 올바른 순서대로 contents를 그리기 위해 존재한다.
- 렌더 트리 생성이 끝나면 배치가 시작되고 그 다음 UI 백엔드에서 각 노드를 가로지르며 형상을 만들어 낸다.
- 렌덜이 엔진은 빠르게 내용을 표시하기 위해서 모든 HTML을 파싱할 때까지 기다리지 않고 배치와 그리기 과정을 시작한다.
파싱과 DOM 트리 구축
파싱 일반
- 문서 파싱은 브라우저가 코드를 이해하고 사용할 수 있는 구조로 변환하는 것을 의미한다.
- 변환된 결과를 Parse tree, syntax tree라고 한다.
- 아래 트리는 2+3-1을 표현한 트리이다.
- 파싱은 어휘 분석과 구문 분석 2가지로 구분이 가능하다.
1. 어휘 분석: 자료를 토큰으로 분해하는 과정을 말한다.
2. 구문분석: 언어의 구문 규칙을 적용하는 과정을 말한다.
- 문서 소스를 받으면 파서는 어휘 분석을 통해 공백과 줄 바꿈 같은 의미 없는 문자들을 제거 후 토큰으로 분해한다. 그 후 구문 분석으로 파싱 트리를 생성한다.
- 어휘 분석기로 부터 토큰을 받아서 구문 규칙과 일치하는지 확인하여 맞으면 토큰에 해당하는 노드가 파싱 트리에 추가되고 또 다른 토큰을 요청한다.
- 일치하지 않는 경우 토큰을 내부적으로 저장하고 토큰과 일치하는 규칙이 발견될 때까지 요청한다.
- 맞는 규칙이 없는 경우 "구문 오류"가 있다는 것을 알려주는 것이다.
변환
- 컴파일러는 만들어진 파싱 트리를 기계 코드로 변환한다.
HTML 파서
- HTML 마크업을 파싱 트리로 변환한다.
- HTML은 파서가 요구하는 문맥 자유 문법에 의해 쉽게 정의할 수 없다.
- 그러나 파싱은 CS와 자바스크립트를 파싱하는데 사용된다.
- HTML을 암묵적으로 태그에 대한 생략이 가능하다.(시작, 종료 태그 생략 등)
- 웹 제작을 편하게 만들어주었지만 공식적인 문법으로 작성하기 어렵게 만드는 문제가 있다.
- HTML을 파싱하기 어렵고 전통적인 구문 분석이 불가능해서 문맥 자유 문법이 아니다.
파싱 알고리즘
- HTML이 일반적이 파서로 파싱이 어려운 이유
1. 언어의 너그러운 속성
2. HTML 오류에 대한 브라우저의 관용
3. 변경에 의한 재파싱, HTML에서 document.write를 포함하고 있는 스크립트 태그는 토큰을 추가할 수 있어 입력 과정에서 파싱이 수정이 된다.
- 브라우저는 HTML 파싱을 위해 별도의 파서를 생성하며 알고리즘은 토큰화와 트리 구축 2단계로 이루어져 있다.
*토큰화
- 어휘 분석으로 입력값을 토큰으로 파싱, HTML에서 토큰을 시작 태그, 종료 태그, 속성 이름과 속성 값 토큰을 인지해서 트리 생성자로 넘기고 다른 토큰을 확인하기 위해 다음 문자를 확인, 이 과정을 입력 마지막까지 반복한다.
트리 구축 알고리즘
- 파서가 생성되면 문서 객체가 생성된다. 트리 구축이 진행되는 종안 문서 최상단에서는 DOM 트리가 수정되고 요소가 추가된다.
- 토큰화에 의해 발행된 각 노드는 트리 생성자에 의해 처리된다.
- DOM 트리에 요소를 추가하는 것이 아니라면 열린 요소는 스택(임시 버퍼 저장소)에 추가된다.
예시) 트리 구축
<html>
<body>
Hello world
</body>
</html>
- "html 이전" / html 토큰은 HTMLHtmlElement 요소를 생성하고 문서 객체의 최상단에 추가한다.
- "head 이전" / body 토큰을 받는다. head 토큰이 없더라도 HTMLHeadElement는 묵시적으로 생성되어 트리에 추가된다.
- "head 안쪽"으로 변경 후 바로 다시 "head 다음"으로 변경 / body 토큰이 처리되고 HTMLBodyElement가 생성되어 추가됐다.
- "body 안쪽" / :Hello world" 문자열의 문자 토큰을 받는다. 각 문자를 위한 문자 토큰을 받게 되는데, 첫 번째 토큰이 생성되고 "본문" 노드가 추가되면서 다른 문자들이 그 노드에 추가된다.
- "body 다음". / html 종료 태그를 만나면 "body 다음 다음" 모드로 바뀌고 마지막 파일 토큰 받으면 파싱 종료된다
- 파싱 이후에는 문서 파싱 이후 실행되어야 하는 "지연"모드 스크립트를 파싱한다.
- 문서 상태는 "완료"가 되고 "로드"이벤트가 발생한다.
스크립트와 스타일 시트의 진행 순서
스크립트
- Web: 파싱과 실행이 동시에 수행되는 동기화 모델
- 파서가 <script> 태그를 만나면 실행을 하고, 스크립트가 실행되는 동안 문서의 파싱은 중단된다.
- 개발자가 스크립트를 "지연(defer)로 표시하면 문서 파싱은 중단되지 않고 문서 파싱이 완료된 이후에 스크립트가 실행된다. (스크립트 fetching은 병렬적으로 동작한다.)
예측 파싱
- 웹킷이나 파이어폭스는 예측 파싱과 같은 최적화를 지원한다.
- 스크립트를 실행하는 동안 다른 스레드는 네트워크로부터 다른 자원을 찾아 내려받고 문서의 나머지 부분을 파싱한다.
스타일 시트
- CSS 파일이 파싱되면 생성되는 것을 스타일 시트 객체라고 말한다.
- 이론적으로는 스타일 시트는 DOM 트리를 변경하지 않기 때문에 문서 파싱을 기다리거나 중단할 이유가 없다.
- But, 스크립트가 문서를 파싱하는 동안 스타일 정보를 요청하면 문제가 된다. 따라서 파이어폭스는 로드중이거나 파싱 중인 스타일 시트가 있으면 모든 스크립트의 실행 중단한다.
- 웹킷은 로드되지 않은 스타일 시트 가운데 문제가 될만한 속성이 있을 때만 스크립트 중단한다.
렌더 트리 구축
- DOM 트리가 구축되는 동안 브라우저는 렌더 트리를 구축한다.
- 표시해야할 순서와 문서의 시각적인 구성 요소로써 올바른 순서로 내용을 그려내기 위한 목적이 있다.
- 각 렌더러는 CSS2 명세에 따라 CSS 박스에 부합하는 사각형을 표시. 렌더러는 너비, 높이, 위치와 같은 기하학적 정보를 포함한다.
* 파이어폭스는 이 구성요소를 "형상(frames)" 라고 부르고 웹킷은 "렌더러(renderer)"또는 렌더 객체(render object)"라는 용어를 사용한다.
DOM 트리와 렌더 트리의 관계
- 렌더러는 DOM 요소에 부합하지만 1:1 대응은 아니다.
- ex) head 요소와 같은 비시각적 DOM 요소는 렌더 트리에 추가되지 않고, display 속성에 none값이 할당 된 요소도 트리에 나타나지 않는다.
-하나의 사각형으로 묘사할 수 없는 복잡한 구조는 여러 개의 시각 객체와 DOM 요소가 대응한다.
트리를 구축하는 과정
1. 파이어폭스 : 프레젠테이션을 DOM 업데이트를 위한 리스너로 등록한다.
2. 웹킷 : 모든 DOM 노드에 attach 매서드가 있다. DOM 트리에 노드를 추가하면 새 노드의 attach 메소드를 호출하고, attach 메소드는 스타일을 결정하고 렌더러를 만든다.
3. html 태그와 body 태그를 처리함으로써 렌더 트리 루트를 구성. 트리의 나머지 부분은 DOM 노드를 추가함으로써 구축된다.
스타일 계산
- 렌더 트리를 구축하려면 각 렌더 객체의 시각적 속성에 대한 계산이 필요하다.
- 스타일은 인라인 스타일 요소와 HTML의 시각적 속성과 같은 다양한 형태의 스타일 시트 포함한다.
- HTML의 시각적 속성은 대응하는 CSS 스타일 속성으로 변환된다.
- 스타일 계산하는 일에는 3가지 어려움이 따른다.
- 수 많은 스타일 속성들을 수용하면서 메모리 문제 야기할 수 있다.
- 최적화되어 있지 않다면 각 요소에 할당된 규칙을 찾는 것은 성능 문제를 야기할 수 있다.
- 규칙을 적용하는 것은 계층 구조를 파악해야 하는 다단게 규칙 수반한다.
<해결 방법>
1. 웹킷 노드: 스타일 객체를 참조하며. 스타일 객체는 일정 조건 아래 공유할 수 있다.
2. 파이어폭스: 스타일 계산을 쉽게 처리하기 위해 규칙 트리와 스타일 문맥 트리라고 하는 두 개의 트리 더 가지고 있다.
배치
- 배치, 리플로: 렌더러가 생성되어 트리에 추가될 때 크기위 위치 정보는 없는데 이런 값을 계산하는 것
- HTML은 흐름 기반의 배치 모델 사용하는데 단일 경로를 통해 크기와 위치 정보를 계산할 수 있다는 것을 의미한다.
- 이런 흐름속에서 나중에 등장하는 요소는 앞서 등장한 요소의 위치와 크기에 영향을 미치지 않기에 배치는 왼쪽에서 오른쪽 혹은 위에서 아래로 흐른다.
- 단, 표는 하나 이상의 경로를 필요로 하기 때문에 예외가 된다.
- 배치는 <html> 요소에 해당하는 최상위 렌더러에서 시작한다.
- 모든 렌더러는 "배치" 또는 "리플로" 메서드를 갖는다. 각 렌더러는 배치해야 할 자식의 배치 메소드를 불러온다.
더티 비트 체제
- 작은 변경 때문에 전체를 다시 배치하지 않기 위해 브라우저는 더티 비트 체제 사용한다.
- 렌더러는 다시 배치할 필요가 있는 변경 요소 또는 추가된 것과 그 자식을 "더티"라고 표시한다.
전역 배치와 점증 배치
- 배치는 렌더러 트리 전체에서 일어날 수 있는데 이것을 "전역"배치라고 한다.
- 글꼴 크기 변경과 같이 모든 렌더러에 영향을 주는 전역 스타일 변경
- 화면 크기 변경에 의한 결과
- 더티 렌더러가 배치되는 경우에만 비동기적으로 점증 배치가 된다.
ex) 네트워크로부터 추가 내용을 받아 DOM 트리에 더해진 다음 새로운 렌더러가 렌더 트리에 붙을 때
비동기 배치와 동기 배치
- 점증 배치는 비동기로 실행된다.
- "offsetHeight"과 같은 스타일 정보를 요청하는 스크립트는 동기적으로 점증 배치를 실행하기도 한다.
- 전역 배치는 보통 동기적으로 실행된다.
최적화
- 배치가 "크기 변경" 또는 렌더러 위치 변화 때문에 실행되는 경우 렌더러의 크기는 다시 계산하지 않고 캐시로부터 가져온다.
배치과정
- 부모 렌더러가 자신의 너비를 결정
- 부모가 자식을 검토
- 자식 렌더러를 배치(자식의 x, y 설정)
- (부모와 자식이 더티하거나 전역 배치 등의 이유로) 필요하다면 자식 배치를 호출하여 자식의 높이 계산
- 부모는 자식의 누적된 높이와 여백, 패딩을 사용하여 자신의 높이를 설정. 이 값을 부모 렌더러의 부모가 사용
- 더티 비트 플래그 제거
너비 계산
- 렌더러의 너비는 포함하는 블록의 너비, 그리고 렌더러의 너비와 여백, 테두리를 이용하여 계산된다.
줄바꿈
- 렌더러가 배치되는 동안 줄을 바꿀 필요가 있을 때 배치는 중단되고 줄 바꿀 필요가 있음을 부모에게 전달한다.
그리기
- 화면에 내용을 표시하기 위한 렌더 트리가 탐색되고 렌더러의 "paint" 메서드 호출.
전역과 점증
- 배치와 마찬가지로 전역 또는 점증 방식으로 수행한다.
- 점증
1. 점증 그리기에서 일부 렌더러는 전체 트리에 영향을 주지 않는 방식으로 변경된다.
2. 이때 변경된 렌더는 화면 위의 사각형을 무효화 하고 OS는 이것을 "더티" 영역으로 보고 "paint" 이벤트 발생시킨다.
그리기 순서
- 배경 색
- 배경 이미지
- 테두리
- 자식
- 아웃라인
동적 변경
브라우저는 변경에 대해 최소한의 동작으로 반응하려고 노력한다.
- 요소 색깔 변경 : 해당 요소 리페인팅만 발생
- 요소 위치 변경 : 요소, 자식, 형제의 리페인팅과 재배치 발생
- DOM 노드 추가 : 노드의 리페인팅과 재 배치 발생
- html 요소의 글꼴 크기를 변경하는 것과 같은 큰 변경은 캐시를 무효화하고 트리 전체의 배치와 리페인팅이 발생한다.
렌더링 엔진의 스레드
- 렌더링 엔진은 통신을 제외한 거의 모든 경우에 단일 스레드로 동작한다.
- 통신의 경우 병렬 연결의 수는 2~6개로 제한된다.(파이어폭스 3은 6개를 사용)
이벤트 순환
- 브라우저의 주요 스레드는 이벤트 순환으로 처리 과정을 유지하기 위해 무한 순환된다. 배치와 그리기 같은 이벤트를 위해 대기하고 이벤트를 처리한다.
참고자료
https://d2.naver.com/helloworld/59361
https://www.html5rocks.com/en/tutorials/internals/howbrowserswork/
'Technology > Other technic' 카테고리의 다른 글
WEBGL을 이용한 삼각형 그리기 (0) | 2022.11.20 |
---|---|
WebGL (0) | 2022.11.16 |
티스토리에 Code Highlight 설정 방법(2017.04.24 version) (0) | 2017.04.24 |