브라우저 렌더링 Browser rendering
브라우저는 'content (콘텐츠)' 를 'rendering (렌더링)' 해서 'pixel image(픽셀 이미지)' 즉 화면을 만듭니다.
- 브라우저 렌더링 Browser rendering - 0단계 소개
- 브라우저 렌더링 Browser rendering - 1단계 파싱 'parse'
- 브라우저 렌더링 Browser rendering - 2단계 스타일링 'style'
- 브라우저 렌더링 Browser rendering - 3단계 레이아웃 'layout'
- 브라우저 렌더링 Browser rendering - 4단계 페인팅 'paint'
- 브라우저 렌더링 Browser rendering - 5단계 변경 'change'
렌더링 파이프라인 Rendering pipeline
5단계 변경 'change'
1 단계 '파싱'부터 4단계 '페인팅' 까지 열심히 작업해서 화면에 표시할 이미지를 만들었는데 브라우저를 스크롤하거나 줌하거나 자바스크립트 코드로 문서를 변경해버리면, 다시 이미지를 렌더링해야 합니다. 그런데 브라우저의 렌더링 과정은 복잡하며 시간과 메모리를 많이 차지하는 작업이라 맨 처음부터 다시 만들 수는 없습니다. 어떻게든 지금까지 열심히 만든 것을 최대한 재활용하고 변경된 내용만 빠르게 반영하여 이미지를 만들어야 합니다.
브라우저의 렌더링은 하나의 이미지를 만들기 위한 과정이 아닙니다. 위 그림에 선글라스를 낀 아이콘의 이미지가 시간에 따라 회전하듯이, 브라우저의 렌더링도 사용자와의 인터렉션을 통해 변화하는 과정입니다. 일반적으로 모니터의 주사율은 60Hz 로 1초에 60장의 이미지를 화면에 뿌려줍니다. 만약 브라우저 렌더링이 모니터의 주사율 이하 또는 화면이 끊긴다는 걸 인지하는 30Hz 이하로 이미지를 만들어서 화면에 뿌리면 '랙'이 걸린다고 느끼게 됩니다.
'VSync signal' 은 모니터에 정해진 주사율에 맞춰 화면 업데이트 타이밍을 맞추기 위한 신호입니다. 끝도 없는 그래픽의 세계..
유효성 검사 Invalidation
따라서 브라우저의 화면이 버벅거리지 않도록 하기 위해서는 업데이트해야 할 부분을 최소화해서 반영해야 합니다. 브라우저 렌더링 엔진 Blink 는 렌더링 파이프라인 단계 별로 'invalidation' 즉 유효성을 검사해서 업데이트가 필요한 부분의 데이터만 변경합니다.
레이어 합성 compositing
유효성 검사로만으로는 유효한 성능을 확보하기가 어렵습니다. 특히 스크롤 이벤트 같은 경우 화면 전체가 움직이기 때문에 유효성 검사의 효과가 미미합니다. 그래서 도입한 방법이 레이어 합성 (compositing) 입니다. 화면을 구성하는 요소를 레이어 별로 쪼개서 이미지를 만든 뒤 화면에 합쳐서 표현하는 방법을 '레이어 합성' 이라고 합니다. 이미 레이어 합성은 영상 처리 기술로서 널리 알려져 있기 때문에 브라우저 렌더링에만 국한된 방법은 아닙니다.
큰 화면을 레이어로 쪼개서 작업하고 관리하면 화면에 애니메이션을 효율적으로 표현할 수 있게 됩니다. 만약 화면 전체를 렌더링하면 화면 일부에 나타나는 애니메이션을 표현하기 위해 전체 이미지를 계속 다시 그려야 하지만, 레이어로 쪼개서 렌더링하면 애니메이션이 반영된 레이어의 이미지만 업데이트하고 레이어를 합성하면 전체 화면을 다시 그리는 것보다 훨씬 효과적입니다.
위 그림처럼 레이아웃 트리의 특정 노드를 기준으로 해서 GraphicsLayer
가 되는 후보인 PaintLayer
를 만들고, 화면을 구성하기로 선택된 일부 PaintLayer
가 GraphicsLayer
가 되어 LayerTreeHost
에 저장되어 관리됩니다.
위 그림은 성능 향상을 위해 각 레이어를 다른 스레드에서 그리는 과정을 파이프라인에 추가한 그림입니다. 레이아웃 단계가 완료되고 나서 여러 PaintLayer
들 중 GraphicsLayer
를 결정하고 각 레이어 별로 스레드가 할당되어 화면에 표시할 일부분의 이미지를 만들게 됩니다.
레이어 타일링 tiling
안타깝게도 레이어 합성만으로도 충분한 성능을 확보할 수가 없습니다. 왜냐하면 화면을 거의 차지하는 스크롤 레이어가 있다면 레이어가 너무 커서 레이어 합성의 효과가 미미해지기 때문입니다. 그래서 레이어를 더 작은 단위인 타일로 쪼개고 타일의 위치나 특성에 따라 우선순위를 매겨 각 타일별 이미지를 만듭니다. 예를 들어 레이어의 타일 중 현재 화면에 나타나지 않을 부분은 아직 보이지 않기 때문에 나중에 이미지를 만듭니다.
활성화 activation
이렇게 힙겹게 만들어진 레이어 이미지는 먼저 'pending tree' 에 commit
되고, 다음 'draw' 이벤트 전에 레이어를 합성하여 레스터라이징합니다. 레스터라이징이 끝나서 실제 화면에 표현할 준비가 되면 activation
작업을 통해 'pedding tree' 를 'active tree' 에 반영합니다. 'active tree' 는 특정 간격마다 draw
작업을 진행해서 렌더링된 이미지를 화면에 뿌립니다.
요약
이제 모든 과정이 끝났습니다. 모든 단계를 요약하면 위 그림과 같이 진행됩니다. 서버에서 가져온 콘텐츠를 렌더링 엔진이 받아서 파싱해 문서를 만들고, 스타일을 반영하고, 레이아웃을 계산하고, 레이아웃을 레이어로 쪼개서 다른 스레드로 넘기고, 레이어를 타일로 쪼개서 이미지를 만들어 합치고, 레이어도 합성해서 화면 이미지를 만들고 브라우저 화면에 그리기까지 브라우저 렌더링 단계를 드디어 모두 마쳤습니다!
마치며...
여기까지 읽어 주신 분이 계시다면 긴 글을 읽느라 정말 고생하셨습니다. 저의 부족한 글 솜씨로 인해 힘드셨을 텐데 끝까지 읽어 주셔서 정말 감사하다는 말씀드리고 싶네요...
'Develop > Frontend 가이드' 카테고리의 다른 글
[FE] JavaScript 완벽 가이드, ECMAScript 를 읽는 방법 (2/2) (0) | 2021.04.03 |
---|---|
[FE] JavaScript 완벽 가이드, ECMAScript 를 읽는 방법 (1/2) (0) | 2021.04.02 |
[FE] 브라우저 렌더링 Browser rendering - 4단계 페인팅 'paint' (0) | 2021.03.30 |
[FE] 브라우저 렌더링 Browser rendering - 3단계 레이아웃 'layout' (0) | 2021.03.27 |
[FE] 브라우저 렌더링 Browser rendering - 2단계 스타일링 'style' (0) | 2021.03.27 |
꾸준히 노력하는 개발자 "김예건" 입니다.