이 글은 Tali Garsiel의 "How Browsers Work: Behind the scenes of modern web browsers"를 번역한 글입니다.
Painting
단계에서는, Render tree
를 순회하면서 renderer
의 painting()
메소드를 호출합니다.
Layout
과 마찬가지로, Global painting
과 Incremental painting
이 있습니다. Incremental painting
은 renderer
가 전체 트리에 영향을 미치지 않는 수준에서 변경됩니다. 변경된 renderer
는 사각형을 무효화시키고, 이는 OS가 영역을 dirty
하다고 인식하고 paint()
메소드를 호출합니다. OS는 멍청하게 하나하나 처리하는 것이 아니고, 몇 개의 영역을 하나로 합쳐서 처리합니다. Chrome에서는 render
가 메인 프로세스에 있는 것이 아니기 때문에, 더욱 복잡합니다. Chrome은 OS의 동작을 따라하고, presentation
은 여기서 발생한 이벤트를 Render root
로 전달합니다. 트리는 이벤트와 관련 있는 renderer
에 도달할 때까지 트리를 순회하고, 이를 repaint
합니다.
CSS 명세에는 painting
의 순서가 정의되어 있습니다. 이는 stacking context
에 쌓이는 순서입니다. Block renderer
가 스택에 쌓이는 순서는 아래와 같습니다.
Firefox는 Render Tree
로부터 이미 그려진 사각형들의 display list
를 생성합니다. 이 리스트는 background
, border
와 같은 사각형과 관련된 renderer
를 올바른 순서대로 가지고 있습니다. 리스트 덕분에, 트리를 한 번만 순회하면서 repaint
과정을 진행할 수 있습니다.
Firexfox는 다른 elemnts
아래 깔린 elements
와 같이 보이지 않을 elements
를 추가하지 않는 방법으로 최적화를 진행합니다.
Webkit은 repaint
될 사각형을 bitmap
으로 저장합니다. 그리고 새로운 사각형과 비교해서 다른 부분만 repaint
합니다.
브라우저는 color
의 변화는 element
만 repaint
하는 것과 같이 최소한의 액션으로 변화에 반응하려 합니다. position
의 변화는 element
뿐만 아니라 자식 그리고 형제의 layout
과 repaint
를 발생시킵니다. DOM 노드를 추가하면 노드의 layout
과 repaint
를 발생합니다. html element
의 폰트 사이즈를 변경하는 것 같은 큰 변경이 발생하면 캐시는 무효화되고, render tree
전체의 relayout
과 repaint
가 일어납니다.
Rendering engine
은 싱글 스레드로 돌아갑니다. 네트워크 통신과 같은 작업을 제외하면 대부분의 작업은 이 스레드에서 돌아갑니다. Firefox와 Safari에서 Rendring engine
은 브라우저의 메인 스레드입니다. Chrome은 각 탭의 메인 스레드입니다. 네트워크 통신은 다른 몇 개의 스레드에세 돌아가고, 이 스레드는 주로 2~6개로 개수가 제한됩니다.
브라우저의 메인 스레드는 event loop
라고 부릅니다. 이는 프로세스를 계속 돌아가게 하는 무한 루프로, layout
과 paint
와 같은 이벤트가 발생하면 이를 처리합니다. Firefox의 코드는 아래와 같습니다.
while (!mExiting)
NS_ProcessNextEvent(thread);
참고 자료
How Browsers Work: Behind the scenes of modern web browsers
브라우저는 어떻게 동작하는가?