TIL21. 브라우저의 렌더링 처리 과정(1)

15271 단어 JavaScriptCSShtmlCSS

Today I Learnd

오늘은 과제를 하다 말고 브라우저가 어떤 과정을 거쳐 렌더링을 하게 되는지 알아보았다. 가벼운 마음으로 알아 보았다가 큰 코를 다치고 말았다... html 파싱부터 생소한 개념이 많았고, 머리속이 복잡하여 정리하는 마음으로 이 글을 적게 되었다.

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

브라우저는 다음과 같은 과정으로 우리에게 화면을 보여준다.

  1. html 파싱을 통해 DOMTree를 생성한다.
  2. CSS를 파싱하여 CSSOMTree를 생성한다.
  3. 파싱된 DOMTreeCSSOMTree를 합쳐 렌더 트리를 형성한다. 이 과정을 어태치먼트(attachment)라고 한다.
  4. 렌더 트리를 바탕으로 DOM을 배치한다. 이 과정은 webkit 기준으로 layout이라고 하고, gecko 기준으로는 reflow라고 한다.
  5. DOM을 그린다. 이 과정을 paint라고 한다.

오늘은 1번, 그리고 2번 조금정도? 써 보려고 한다.

html 파싱 과정

그리고 html 파싱 과정은 비동기적인 과정이다. 모든 html을 서버에서 불러올 때 까지 기다리지 않고 먼저 받아온 데이터들 먼저 처리하여 동작 시간을 줄인다.

html 파싱은 크게 두 가지 과정을 거친다.
1. 어휘 분석 (토큰화)
2. 구문 분석 (Tree 구축)

어휘 분석은 주어진 html을 토큰화 하는 과정이다. 토크나이저를 통해 html을 유효한 토큰으로 변환한다.

토큰이란, 유효하게 구성된 단위의 집합체를 뜻한다.

일반적인 문맥 자유 문법 언어는 베커스-나우스 표기법인 상세 규칙이 존재하여, 기존의 파싱인 상향식 파싱이나 하향식 파싱 방법을 통해 파싱이 가능하다. 그러나, html은 문맥 자유 문법이 아니기 때문에 기존의 파서를 이용하여 토큰화 하는 것이 어렵다.

html을 전통적인 파서를 사용하여 파싱이 불가능한 이유?

이유는 다른 언어와 차별화된 특징을 갖기 때문이다.
1. html은 오류에 관대하다. 따라서 문법상의 오류가 있더라도 오류를 발생시키지 않는다.
2. 잘못 중첩된 태그나 닫히지 않은 태그들을 알아서 처리하여 DOM을 만들어준다.
3. 스크립트의 document.write()로 실시간으로 DOM이 변경되므로 재 파싱이 필요하다.

따라서 html은 토큰화 + Tree 구축 과정을 통해 DOMTree를 구성하게 된다.

html 토큰화 과정

html은 다음의 과정을 거쳐 토큰화가 이루어진다. 처음 토크나이저의 상태는 자료 상태를 갖는다.(자료를 읽어들이는 상태라고 생각하자)
1. 토크나이저가 <를 만난다. 토크나이저의 상태가 태그 읽음 상태로 바뀐다.
2. 토크나이저가 태그를 읽어들이고, >를 만나면 태그 토큰을 발행하고, 다시 자료 상태로 바뀐다.
3. 자료 상태인 토크나이저가 자료들을 읽어들인다.
4. 토크나이저가 <를 만나면, 자료 토큰을 발행하고 태그 읽음 상태로 바뀐다.
5. /를 만나면, 태그 닫힘 상태가 되고 태그들을 읽어들인다. 마지막으로 >를 만나면 태그 종료 토큰을 발행한다.

주의: 하부 내용은 이해를 돕기 위한 시각적 자료이지, 실제로 토큰화가 이루어지면 다음의 형태로 토큰화가 된다는 것이 아닙니다.

<html>
    <head>
        <title>My HTML Page</title>
    </head>
    <body>
        <p style="special">
            This paragraph has special style
        </p>
        <p>
            This paragraph is not special
        </p>
    </body>
</html>

이러한 html 구조를 갖는 파일이 있다고 가정하자. 그러면 토크나이저는 일련의 과정들을 거친 뒤 다음 모양의 배열을 만들 수 있을 것이다.

["<", "html", ">", 
     "<", "head", ">", 
         "<", "title", ">", "My HTML Page", "</", "title", ">",
     "</", "head", ">",
     "<", "body", ">",
         "<", "p", "style", "=", "\"", "special", "\"", ">",
            "This paragraph has special style",
        "</", "p", ">",
        "<", "p", ">",
            "This paragraph is not special",
        "</", "p", ">",
    "</", "body", ">",
"</", "html", ">"
]

그리고 또 다른 higher-level 과정을 거쳐 다음의 형태로 만들어질 수 있을 것이다.

[("<html>", {}), 
     ("<head>", {}), 
         ("<title>", {}), "My HTML Page", "</title>",
     "</head>",
     ("<body>", {}),
        ("<p>", {"style": "special"}),
            "This paragraph has special style",
        "</p>",
        ("<p>", {}),
            "This paragraph is not special",
        "</p>",
    "</body>",
"</html>"
]

최종적으로는 트리를 만들기 위하여 다음의 형태를 만들 것이다.

("<html>", {}, [
    ("<head>", {}, [
        ("<title>", {}, ["My HTML Page"]),
    ]), 
    ("<body>", {}, [
        ("<p>", {"style": "special"}, ["This paragraph has special style"]),
        ("<p>", {}, ["This paragraph is not special"]),
    ]),
])

트리 구축 과정

트리 구축 과정은 토큰화 과정으로 생성된 토큰을 바탕으로 DOM Tree를 구축하는 과정이다. 가장 상위 element로는 document가 생성되고, 그 다음 하위 요소들이 생성되고 트리의 수정이 발생한다. 이 과정에서 부정확한 중첩과 종료되지 않은 태그들을 교정하는 과정이 동시에 이루어진다.

파싱이 처리할 수 있는 오류들

  1. 중첩이 금지된 태그를 추가하려고 할 때, 허용된 태그는 닫고 금지된 태그는 밖으로 빼낸다.
  2. 인라인 요소 태그 안쪽에 블럭 요소 태그를 추가하려고 할 때, 부모 블록 요소들을 만날 때까지 인라인 요소들을 닫는다.
  3. 이러한 방법이 도움이 되지 않는다면, 태그를 추가하거나 무시할 수 있는 상태가 될 때까지 태그를 닫는다.

-- 이 모든 과정에서 요소의 추가가 일어나지 않는다. document.write()를 통해 언제든지 재배열될 수 있기 때문이다.

파싱이 끝난 뒤..

파싱이 끝나면 브라우저는 이제 문서와 상호작용을 할 수 있게 된다.
브라우저는 파싱 이후에 실행되어야 하는 '지연' 모드의 스크립트를 실행한다.
문서 상태는 완료 상태가 되고, load 이벤트를 실행한다.

CSS 파싱

CSS는 html과 달리, 문맥 자유 문법 언어이고, 따라서 기존 방식의 파서를 이용할 수 있다. 파서의 종류는 브라우저에 따라서 다르다. (webkit은 Flex, bison 파서를 이용한다.)

CSS 파싱을 통하여 CSSOM Tree를 구축한다. CCSOM 트리의 각 객체는 CSS 규칙을 포함한다. (CSS selector, 선언 객체, CSS 문법과 일치하는 다른 객체도 포함.)

마치며

브라우저 렌더링 과정을 정리하고 있지만, 아직도 많이 어렵다. 내가 스스로 설명하고, 나아가 그 현상이 왜 일어나는지 까지 정리하려는 노력을 꼭 해야겠다.

좋은 웹페이지 즐겨찾기