개발 이야기/프론트엔드 개발자

1) 브라우저는 어떻게 동작하는가?

석구석구 2016. 8. 29. 12:51

클라이언트 개발자


https://docs.google.com/spreadsheets/d/1LsA26TE0y3ObdalcH4kuQlnhohH7zRcgVatJziTMpOY/edit#gid=0


http://tryhelloworld.co.kr/courses/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9E%85%EB%AC%B8


참조) http://d2.naver.com/helloworld/59361



Chap1. 브라우저는 어떻게 동작하는가? 



1) 브라우저의 주요 기능


브라우저는 사용자가 선택한 자원을 서버에 요청하고 이를 표현한다. 자원의 주소는 URI에 의해 정해진다.


브라우저는 HTML과 CSS 명세에 따라 HTML파일을 해석하고 표시한다. 이러한 명세는 W3C에서 정한다.


과거에는 브라우저들이 일부만 이러한 명세를 따라 구현하고 독자정인 방법으로 기능을 확장해 왔지만 최근에는 대부분의 브라우저가 표준명세를 따른다.



2) 브라우저의 동작 과정




  1. 사용자 인터페이스 : 주소 표시줄, 이전/다음, 북마크 등.
  2. 브라우저 엔진 : 사용자 인터페이스와 렌더링 엔진 사이의 동작 제어.
  3. 렌더링 엔진 : HTML, CSS을 파싱하고 화면에 표시.
  4. 통신 : HTTP 요청과 같은 네트워크 호출. 플랫폼 독립적이고 각 플랫폼의 하부에서 실행.
  5. UI 백엔드 : 콤보박스와 창 같은 기본적인 장치를 그린다.
  6. JS 해석기 : JS 코드를 해석하고 실행.
  7. 자료 저장소 : 쿠키 저장처럼 모든 종류의 자원을 저장.

3) 랜더링 엔진


요청받은 내용을 브라우저 화면에 표시

HTML, XML, 이미지 등을 표시.


파이어폭스: 게코엔진 | 사파리, 크롬 : 웹킷엔진


랜더링 엔진의 동작 과정




  1. HTML 문서를 파싱하고 콘텐츠 트리 내부에서 태그를 DOM 노드로 변환한다.
  2. 외부 CSS파일과 함께 스타일 요소를 파싱한다.
  3. 스타일 정보와 HTML 표시 규칙으로 렌더트리를 생성한다. 렌더트리는 색상과 면적과 같은 시각적 속성이 있는 사각형을 포함하고 있고, 정해진 순서대로 화면에 표시된다.
  4. 렌더 트리 생성이 끝나면 각 노드를 화면의 정확한 위치에 배치시킨다.
  5. 일련의 과정들은 점진적으로 진행되며, 렌더링 엔진은 사용자 경험을 위해 모든 HTML 파싱을 기다리지 않고 그리기 과정을 시작한다.

* 구축된 랜더트리를 배치하는 과정 - 리플로우



4) HTML 파서


HTML 마크업을 파싱 트리로 변환한다. 이 파싱트리는 DOM요소와 속성노드의 트리로서 출력 트리가 된다. 트리의 최상위 객체는 문서이다.



5) 파싱이 끝난 이후


브라우저는 문서와 상호작용 가능해 진다. 스크립트 파싱. 문서상태는 완료가 되고 로드 이벤트 발생.



6) 스크립트와 스타일 시트의 진행 순서


- 스크립트


웹은 파싱과 실행이 동기화 모델이다. 때문에 스크립트가 실행되는 동안 문서의 파싱은 중단 된다. 스크립트가 외부에 있는 경우 네트워크로부터 자원을 가져와야 하며, 이를 받을 때까지 파싱은 중단된다. (HTML5 스크립트 비동기 처리 속성 추가)

때문에 사용자 경험을 위해 웹킷과 파폭은 예측 파싱을 지원한다. 한 스크립트를 실행하는 동안 다른 스크립트는 별도의 스레드로 이를 병렬처리한다.

여기서 중요한 것은 스크립트가 DOM트리를 수정할 가능성이 있다는 것이다.


- 스타일 시트


스타일시트는 DOM트리를 변경하지 않기 때문에 문서 파싱을 기다리거나 중단할 이유가 없다. 그러나 스타일 시트가 파싱되지 않은 상태라면 스크립트의 결과가 달라질 수도 있으므로 스타일시트가 파싱되지 않은 상태라면 스크립트의 실행을 중단한다.



7) 랜더 트리


DOM트리가 구축되는 동안 브라우저는 렌더 트리를 구축한다. 표시해야 할 순서와 문서의 시각적인 구성 요서로써 올바른 순서로 내용을 그려낼 수 있도록 하기 위한 목적이 있다. 이러한 구성요소를 형상, 렌더러, 렌더 객체라 부른다.

렌더러는 자신과 자식 요소를 어떻게 배치하고 그려내야 하는지 알고 있다.


DOM트리와 렌더 트리는 꼭 1:1 대응하는 관계는 아니다. head와 같은 비시각적 DOM 요소는 렌더트리에 추가 되지 않는다. 또한 DISPLAY 속성이 NONE인 경우에도 렌더 트리에 추가 되지 않는다. (VISIBILITY 속성은 무관하다.)


또한 한 줄에 충분히 표시할 수 없는 문자가 여러 줄로 바뀔 때 새 줄은 별도의 렌더러로 추가 된다.


인라인과 블록 박스가 섞인 경우 인라인 박스를 감싸기 위한 익명의 블록 렌더러가 생성된다.


FLOAT 처리된 요소, 또는 ABSOLUTE와 같은 속성을 가지고 있는 요소는 트리의 동일한 위치에 있지 않다. 자리 표시자가 원래 있어야 할 트리의 위치에 대신한다.




// 랜더 클래스

class RenderObject { 

    void layout(); 

    void paint(PaintInfo); 

    void rect repaintRect();

    Node * node; 

    RenderStyle * style; 

    RenderLayer * containgLayer; 


// 랜더 팩토리

RenderObject* RenderObject::createObject(Node* node, RenderStyle* style)  

{

    Document* doc = node->document();

    RenderArena* arena = doc->renderArena();

    …

    RenderObject* o = 0;

 

    switch (style->display()) {

        case NONE:

            break;

        case INLINE:

            o = new (arena) RenderInline(node);

            break;

        case BLOCK:

            o = new (arena) RenderBlock(node);

            break;

        case INLINE_BLOCK:

            o = new (arena) RenderBlock(node);

            break;

        case LIST_ITEM:

            o = new (arena) RenderListItem(node);

            break;

        ...

    }

    return o;

}



8) 스타일 계산


스타일 데이터는 구성이 매우 광범위하기 때문에 메모리 문제를 야기할 수 있다.

또한 각 요소에 할당된 규칙을 찾는 것은 매우 과중한 업무이기 때문에 성능 문제도 야기할 수 있다.

예를 들어 div div div와 같은 선택자는 트리 탐색과정에서 과중한 업무를 발생시킬 수 있다.

브라우저는 노드가 형제이거나 사촌일 때 공유하며, 일정한 조건을 만족할 때 스타일 객체를 공유할 수 있다.


스타일 계산을 위한 규칙 트리가 있다.

HTML 문맥트리의 각각 노드가, 규칙 트리의 노드 번호를 가짐으로서, 둘의 연결은 이루어 진다.


- p {color:red}

- <p style="color:red"></p>

- <p bgcolor="red"></p>


2번째와 3번째의 경우에는 쉽게 요소에 연결할 수 있다.

하지만 첫 번째의 경우에는 복잡한 규칙처리 과정을 거쳐, 해시맵으로 이루어진 클래스 맵, 아이디 맵, 태그 맵으로 나뉘어 관리된다.


table div {margin:5px}


예를 들어 위와 같은 스타일의 경우 가장 오른쪽의 선택자가 키가 되며, 이를 이용하여 태그맵에서 검색을 수행 하게 된다.


해당 div의 부모 요소중 table이 존재하는지를 확인한 후 스타일 적용 여부를 판단한다.


9) 리플로우


랜더러가 생성되고 트리에 추가될 때 크기와 위치정보는 없는데, 이를 계산하는 것.

일반적으로 흐름 기반의 배치 모델을 사용하게 되고 이는 나중에 등장하는 요소가 앞 요소의 위치와 크기에 영향을 미치지 않기 때문.

때문에 왼쪽에서 오른쪽으로, 위에서 아래로 배치된다. 그러나 테이블의 경우에는 위치를 계산하기 위해 하나 이상의 경로를 필요로 한다. 때문에 예외적으로 처리가 된다.


모든 랜더러는 리플로우 메서드를 가지고 있고 자식의 리플로우 매서드를 불러온다.


전역 리플로우 : 모든 렌더러에 영향을 주는 전역 스타일 변경(ex 전체 글꼴 변경), 화면 크기 변경


점증 리플로우 : 렌더러가 더티일 때 비동기적으로 발생. ex) Ajax로 내용 받아서 Dom 변경, 사용자 반응


offsetHeight와 같은 정보를 요청하는 스크립트는 동기적으로 리플로우를 실행하게 만든다.


10) 페인트


렌더트리를 탐색하고 랜더러의 페인트 페소드가 호출된다.


리페인트 :

렌더러가 변경되면 페인트 이벤트가 발생되며, 이를 프레젠테이션이 감시하고 있다. (옵저버) 그 후 적절한 렌더트리를 탐색하여 해당 영역을 다시 페인트한다.


11) z-index


계층 표현은 스택으로 이루어지며, z-index를 가지고 있는 박스는 지역 스택을 형성한다. 스택의 뒤쪽 요소가 먼저 그려지게 된다.





'개발 이야기 > 프론트엔드 개발자' 카테고리의 다른 글

GET, POST, ...ETC 그리고 HTTP 응답  (0) 2019.06.12
Restful api  (0) 2019.06.12
4) 클라이언트와 서버의 연결  (0) 2016.09.08
3) 메서드  (0) 2016.09.08
2) 브라우저 이벤트  (0) 2016.09.08