카테고리 없음

웹과 브라우저를 위한 프로파일링과 성능 개선

eumjo_o 2023. 1. 31. 22:46
  • Devtools Performance 에서 성능 측정 가능

  • Performance 결과

각 순간의 성능들을 볼 수 있음

  • Network 탭 : 다운로드 요청과 완료 시간을 볼 수 있음
  • Main 탭 : 렌더러의 메인 쓰레드로 다양한 렌더링과 더불어 스크립트 실행도 함
  • FP, FCP, L, DCL, LCP : 로딩 시 하나의 기점이 되는 지표들
  • → paint와 로드 카테고리로 나뉜다

 

 

FP = First Paint

  • 페이지 네비게인션 후 첫 픽셀을 그린 순간

FCP = First contentful paint

  • 첫 엘리먼트를 그린 순간

LCP = Largest contentful paint

  • 가장 큰 엘리먼트를 그린 순간

DCL = Dom Content Loaded

  • Dom Tree를 구성하고, 스크립트( + defer 스크립트)를 실행 완료했을 때,
  • defer 스크립트가 없다면, FP 전에 DCL이 올 수 있다.

LOAD

  • 다큐먼트의 리소스들을 모두 로드 완료했을 때

 

 

브라우저의 렌더링 파이프라인

  • 렌더링 - HTML, CSS, JS, 리소스 등을 실제 화면에 나타내는 과정

 

DOM Parsing

 

  1. 새로운 탭을 클릭 시, Main document를 로딩한다
  2. 렌더러 main thread에서는 태그들을 parsing한다.
  3. parsing 진행 시, 명시된 리소스들을 차례대로 로딩한다.

HTMPDocument Parser가 parsing을 담당한다.

그 후 차례로 토큰화 과정을 거쳐 parsing이 진행되고, script 태그를 만나면 멈춘다.

defer 옵션이 있는 경우는 queue에 넣어두고, parsing 후 나중에 실행한다.

태그들을 파싱하며 Dom Tree가 만들어지는데, 완성되지 않아도 점진적으로 나중에 구성할 수 있다.

Dom 노드들의 개수는 성능에 영향을 미치기 때문에, 개수가 적을수록 좋다.

 

 

STYLE

 

로딩한 css가 도착하면, StyleSheet를 파싱해서 스타일 룰들을 추가해 둔다.

이후 DOM parsing 단계가 끝나면, 모아둔 룰들로 DOM 노드에 대해 ComputedStyle을 계산한다.

점진적으로 Tree를 구성하던 DOM과 달리 꼭 css 계산이 끝나야 다음 단계로 넘어갈 수 있다.

⇒ Css에서 크기과 넓이 등이 결정되기 때문에 그러하다!!!

Render Blocking Resource : 앞으로의 렌더링을 막는다는 의미!!!

css에서 selector를 직접 class를 선택하도록 하면 성능적인 이득을 볼 수 있다.

 

LAYOUT

  • 각 Element들의 크기와 위치를 결정하는 단계

 

  • layout tree가 만들어지는데, 앞의 두 과정이 필수적으로 필요하다.
  • dom tree가 100% 만들어지지는 않아도 되지만, Style 단계에서는 필수적으로 css 계산이 끝나야 한다.
  • 특정 element의 속성을 변경하여 layout이 발생할 때, 전체 document 범위가 layout 되기 때문에 dom 노드 개수를 줄이는 것이 중요하다.

 

LAYER

  • 레이어를 만드는데, 박스 형태이고 움직임의 주체이다.
  • 독립적으로 움직일 수 있다.

UPDATE LAYER TREE

 

  • Prepaint
    • cash된 paint 기록과 달라진 부분은 invalidate하고, scroll과 같은 속성들을 가진 노드들 끼리 따로 구성한 property tree를 만든다.
  • Compositing Assignment
    • 레이어 tree를 build한다.
    • 만들어놓은 layout tree가 compositing한 layout의 후보들인 paint layer가 되고, 이후 compositing할 layout tree가 만들어진다.
    • 이 과정에서 안보이는 자손들은 가장 가까운 조상 노드에 편입되어 그려진다.

PAINT

  • 만들어진 레이어 paint하는 단계
  • 실제로 그림을 그리는 단계가 아니라, drawing command들을 생성하는 단계
    • drawing command - ex) ‘네모를 그려라’, ‘원을 생성해라’
  • drawing command들이 나중에 재생되면서 실제로 그려지고 캐싱된다.

COMPOSITE LAYERS

 

  • 렌더러 process에는 Impl이라 불리는 composite를 위한 thread가 존재한다.
  • layer 합성을 위해 main에 있는 layer들을 compositor thread로 한 장면의 스냅샷을 커밋해 레이어들을 복사해 준다.
  • 복사본을 서로 가지게 되어 main thread는 다른 일을 할 수 있고, compositor thread의 경우는 사용자 이벤트에 빠르게 반응할 수 있게 된다.

PASTER & DRAW

 

  • 각 레이러는 직사각형의 타일들로 나뉘어지고, 타일들은 많은 Raster thread에 의해 각각 bit map이 된다.
  • GPU를 통해서 화면에 그려지게 되는데, 화면에 갱신되는 신호는 Next Vsync에 의해 First Paint가 완성된다.

렌더링 파이프라인

  • 로딩 이후에도 페이지의 동적인 변화에 반응하여 화면을 업데이트하기 위해 항상 웹 페이지와 함께한다.
  • 로딩 시간이 목표이기 때문에 여기서 중요한 것은 첫번째 파이프라인이고, 따라서 첫번째 파이프라인을 최대한 빨리 끝내면서 꼭 필요한 요소들만 보여주게 되면, 좋은 First Paint를 완성할 수 있게 된다.

 

firstPaint를 빠르게!!!

  • 일반적인 css와 script 작동을 네트워크main thread로 나눈다.
  • 예시 코드에서 css 한 개, script 세 개 존재

  • 먼저 요청한 css의 로드가 완료가 되면, stylesheet의 parsing한다.
  • css loading은 main thread의 pasing을 막지 않는다.
  • 하지만, 기본 script는 document.write 등 으로 DOM을 조작할 수 있기 때문에, script 로딩과 실행은 parsing을 하던 main thread를 막아 놓는다. 이렇게 할 시, 위 사진에서 처럼 First paint가 오른쪽 끝에서 완료 된 것을 볼 수 있다.

Q. 그렇다면 어떻게 위 상황을 해결할 수 있는지 …??

DEFER SCRIPT

  • 웹 사이트 로딩 초기에 꼭 필요한 리소스를 style.css와 sync1.js라고 가정해 본다.
  • 이외에 로딩 초기에 필요하지 않은 리소스들은 defer option을 준다.
  • 이 경우, defer1.js와 defer2.js는 background로 다운로드가 되어 parsing을 막지 않는다.
  • defer script는 main thread가 dom parsing 후에 보통 나머지 렌더링 파이프라인까지 진행한 후 화면을 업데이트한 후에 defer script를 실행한다. 따라서 매우 효율적!!!!
  • 하지만, 필수 리소스인 sync1.js를 네트워크 로딩하는 부분이 있기 때문에 main thread는 일부 block 되는 것을 볼 수 있다.

INLINE & ONLOAD

  • 한단계 더 좋게 성능개선을 하려면, critical resource를 inline하면 효과를 극대화할 수 있다.

 

  • client 장비들은 나날이 빨라지는 반면, 네트워크는 상황에 따라서 아직 느릴 수 있다.
  • 따라서, critical resource를 외부 참조하지 않고, html에 inline 삽입하면 request 없이 곧 바로 script를 컴파일하고 실행한다.
  • 그렇다고 해서 큰 리로스를 넣으면 document가 비대해지기 때문에 최대한 필수적인 것으로 간추려서 넣는 것이 좋다.
  • main thread에서 스크립트 로딩 대기시간을 없애고 다른 중요한 일을 할 수 있게 된다.

LCP (Largest Contenful paint)

  • 실제 웹에 그려지는 동작과 타이밍이 다양하기 때문에 LCP의 시점이 정확하지 않을 때가 많다.
  • 따라서, dev tools로 개발자가 직접 performace를 돌리거나 performance observer api로 찍어봐야 하는 상황이 생긴다.

fisrt paint 이후에도 아래 사진에서 알 수 있듯이 script는 계속 동작한다.

이때, main thread의 경우는 렌더링 파이프라인과 script도 실행해야 하는데 만약 script 실행이 길어지면, 한 프레임에 파이프라인을 완성하지 못하고, Jank가 발생한다.

 

wall paper교체 시 시간 단축 시 정비한 사항들

 

  • js에서 필요없는 기다림을 없애고 캐싱을 정비해서 wallpaper script 부분의 로딩을 70% 이상 감소시킴
  • main thread에서 DOM 접근이 필요없는 동작들을 모아 모두 web worker thread를 통과하는 작업을 진행했다.

 

 

 

출처