프론트엔드

『기초부터 완성까지, 프런트엔드』 15. 성능

오늘의 나1 2022. 2. 2. 17:58

15.1 Performance 탭과 성능 최적화

15.1.1 Performance 탭의 구성

크롬 개발자 도구의 Performance 탭에서 웹페이지의 성능을 측정할 수 있다.

특이한 점은 (1)의 새로고침버튼을 누르면 웹페이지를 새로고침해 측정을 시작한다는 것. (2)의 다운로드, 업로드 기능을 통해 성능개선결과를 확인하는 데 이용할 수 있다는 점. (3)의 버튼으로 성능측정할 것을 선택할 수 있다는 것. (4)의 휴지통 버튼을 누르면 가비지컬렉션이 된다는 것. 그리고 (5), (6), (7)의 영역에 성능측정 결과가 나타난다는 점이다.

 

15.1.2 렌더링 블록

렌더링 블록: 렌더링을 막는 것

블록 리소스: 렌더링 블록의 원인이 되는 리소스

 

 

15.1.2.1 CSS의 렌더링 블록

 

렌더링 블록의 원인

 

렌더트리 생성을 위해 CSSOM 트리가 구성되어야 한다. CSSOM 트리는 HTML 트리와 달리 전체가 파싱되어야 구성될 수 있다. 그래서 CSSOM 트리의 생성이 지연되면 렌더링 블록이 생긴다. 

 

성능 개선 방법

  • @import 대신 link를 사용하여 외부 css 파일을 병렬로 로딩 (@import는 병렬 로딩이 안 됨)
  • 번들러를 사용하여 css 파일을 분리하여 필요한 상황에서만 로딩되도록 최적화
  • 초기 뷰포트 영역의 렌더링에 필요한 critical css들만 inline css로 삽입한다. 필요한 css만 로드하여 렌더링 시간이 단축됨 *HTTP2의 서버푸시를 사용할 때 critical css를 사용하면 성능저하의 원인이 될 수 있다. 클라이언트에서 필요한 리소스를 미리 전송해주는 데, critical css를 사용하면 이를 파싱하고 렌더링해야 해서?

 

15.1.2.2 자바스크립트의 렌더링 블록

 

렌더링 블록의 원인

 

HTML 파싱 중 script 태그를 만나면 script 태그의 로딩 및 실행이 완료될 때까지 DOM 트리 생성을 중단한다.

 

성능 개선 방법

  • body 태그 바로 앞에 script 태그를 배치
  • defer와 async 속성을 사용하여 백그라운드 스레드에서 비동기로 다운로드
    • defer 비동기로 다운로드 후 DOMContentLoaded 이벤트 발생 전에 지연 실행. DOM 트리가 완성된 상태에서 실행되기 때문에 DOM 요소에 접근할 수 있음. defer 속성을 가진 스크립트가 여러 개인 경우, 순서대로 실행
    • async 비동기로 다운로드 후, 다운로드 완료되면 즉시 실행. async 스크립트의 실행이 끝날 때까지 HTML 파싱 멈춤. 다른 스크립트와 의존성이 있는 경우는 적합하지 않고, 광고나 데이터 수집처럼 독립적인 역할을 담당하는 외부 스크립트 로딩할 때 좋음
    • IE와 같은 구형 브라우저에서 미지원

 

  • 번들러를 사용하여 CSS나 자바스크립트 파일을 하나로 묶어 리소스 요청을 최적화
  • 트리 셰이킹을 사용하여 불필요한 코드를 제거 
  • 페이지의 초기에 필요없는 자원들은 별도로 분리하여 비동기로 로딩
  • HTML 구조를 간결하게 구성
  • 중복 코드를 최소화
  • 난독화 및 압축을 하여 리소스의 용량 줄이기

 

15.1.3 레이아웃 최소화

 

렌더링 블록의 원인

 

브라우저 렌더링 과정 중 레이아웃 과정을 수행하면, 엘리먼트의 위치를 재계산하고, 이후 Paint와 Composition 과정을 반복하기 때문에 비용이 많이 들어간다. 그러므로 레이아웃 실행을 최소화하여 렌더링 블록을 줄여야 한다.

 

15.1.3.1 강제 동기 레이아웃과 레이아웃 스레싱

 

강제 동기 레이아웃: 레이아웃은 원래 비동기로 수행된다. 그런데, 경우에 따라 레이아웃이 동기로 수행되어 렌더링 시간이 늘어진다. offsetHeight, offsetWidth 같은 속성은 조회하는 것만으로 레이아웃이 수행된다. 이 값을 조회하기 전에 클래스 변경 등으로 CSS를 변경하면, 변경된 스타일이 적용된 후의 값을 반환하기 위해 레이아웃이 실행될 때까지 기다려야 한다. 이는 렌더링 속도를 불필요하게 느려지게 한다. 강제 동기 레이아웃이 일어나는 것을 막기 위해 엘리먼트의 기하학적 속성을 조회하고 나서 스타일 변경을 수행해야 한다.

 

레이아웃 스레싱: 강제 동기 레이아웃이 연속적로 발생하는 것. 강제 동기 레이아웃을 유발하는 코드가 반복문 내에서 불필요하게 실행되는 것을 막아야 한다. 

 

15.2 메모리 관리하기

15.2.1 가비지 컬렉션

V8 엔진 메모리 구조

Stack 영역: 메서드 호출과 관련된 매개변수, 지역변수 등의 데이터를 관리하는 곳

Heap 영역: 동적 메모리 관리하는 곳. 가비지 컬렉션이 일어나는 곳

 

가비지 컬렉션의 기준

 

도달가능성(reachablility)을 기준으로 가비지 컬렉팅이 수행된다. 자바스크립트 엔진은 내부적으로 Mark and Sweep 알고리즘을 사용하여 도달가능성을 판단한다.

 

15.2.2 메모리 누수 탐지하기

크롬 개발자도구의 메모리 탭을 통해 메모리 누수를 탐지할 수 있다. 

특이한 점은 프로파일링 유형이 3가지라는 점이다. 힙 스냅샷은 자밧크립트 객체와 관련된 DOM 노드 사이의 메모리 분포, 타임라인 할당 계측은 시간의 흐름에 따른 메모리 누수 기록, 할당 샘플링은 자바스크립트 함수를 기준으로 메모리를 측정할 수 있다. 

 

타임라인 할당 계측에서 메모리의 할당과 해제를 확인할 수 있다. 할당되고 해제되지 않은 메모리는 파란색, 해제된 메모리는 회색으로 나타난다. 얕은 크기는 객체 자체가 보유한 크기, 유지된 크기는 힙에서의 크기를 의미한다. 해제되지 않은 메모리가 무엇인지 파악할 수 있다.

 

메모리 누수를 방지하기 위한 코딩 습관을 기르면 좋은 데,

타이머를 clearTimeout(), clearInterval()을 통해 할당하고, DOM에 등록한 이벤트를 해제하고, 불필요한 클로저를 사용하지 않도록 한다.

 

15.3 Performance 탭과 Web Vitals

15.3.1 Performance 탭의 다양한 지표들

15.3.1.1 DOMContentLoaded와 Load 이벤트

  • DCL: DomContentLoaded 이벤트 발생 시점. 브라우저가 DOM 트리 구성을 완료 했을 때 발생
  • L: Load 이벤트 발생 시점. DOM 트리뿐만 아니라 CSS, 이미지와 같은 리소스들까지 모두 준비되었을 때 발생
  • 페이지 로딩 완료 시점, 초기에 불필요한 이미지나 CSS 로딩이 존재하는 지 파악하는 용도 

 

15.3.1.2 First Paint와 First Contentful Paint

  • FP: 화면에 어떤 요소를 처음으로 그리기 시작하는 시점. 해당 요소가 사용자에게 보이는 지와는 상관없음
  • FCP: 사용자가 화면에서 무언가를 인식하는 시점. 때문에 로딩 속도를 측정할 때 중요한 지표. 구글 검색 엔진의 SEO에도 영향을 미치기 때문에 웹 사이트의 검색 우선순위를 높이고 싶다면 반드시 최적화를 하는 것이 좋음

 

15.3.2 Web Vitals

15.3.2.1 Largest Contentful Paint(LCP)

  • 페이지의 뷰포트에서 가장 큰 영역을 차지하는 이미지(이미지, svg, 비디오, 배경이미지 등)나 텍스트 블록이 렌더링 되는 시간을 측정
  • 2.5초 이하의 로딩 속도를 만족시켜야 좋은 점수를 얻을 수 있음
  • 페이지에서 크기가 큰 콘텐츠가 다른 콘텐츠에 비해 상대적으로 중요하다는 것을 전체로한 지표
  • FCP는 전체 페이지를 대상으로 측정하기 때문에 해당 시점에 뷰포트 밖에 있다면 사용자에게는 의미가 없는 수치. 또한, 뷰포트 영역에 측정되었더라도 의미없는 엘리먼트일 수 있음

 

15.3.2.2 First Input Delay(FID)

  • 사용자가 처음으로 웹페이지와 인터렉션했을 때 얼마나 빠르게 응답하는 지 느낄 수 있는 지표. 이벤트 리스너의 실행시간이 아닌, 이벤트 리스너가 실행되기까지의 시간을 측정

 

15.3.2.3 Cumulative Layout Shift(CLS)

  • 불필요한 레이아웃의 변경빈도를 측정하여 시각적 안정성을 판단하는 지표

 

15.4 라이트하우스 

웹 사이트의 품질을 측정하는 자동화 도구
웹 페이지의 성능이나 접근성, SEO 등을 자체 기준으로 통해 점수를 매겨 주며 모범 사례를 기준으로 개선점을 알려줌

15.4.2 기준 살펴 보기

15.4.2.1 Performance

  • FCP, LCP, CLS, SI, TTI, TBT 지표 측정. 각 지표에 가중치를 부여해 계산함
  • SI(Speed Index): 뷰표트의 로딩 속도, 모든 엘리먼트를 한 번에 나타내는 것보다 먼저 나타낼 수 있는 것을 점진적으로 보여주는 것이 더 높은 점수를 받게 됨
  • TTI(Time To Interactive): 페이지가 완전히 상호작용할 수 있는 상태가 되는 시점. FCP부터 마지막 Long Task의 종료 시점. 
  • TBT(Total Blocking Time): FCP부터 TTI 시간 동안 총 차단된 시간을 더해 측정

 

15.4.2.2 Best Practices

  • 오래된 관행, 안티패턴을 찾아주고 더 적합한 API로 대체하여 콛를 작성하도록 도와줌

 

15.4.2.3 Accessibility

  • 웹 접근성 지침을 잘 따르는 지 검증

 

15.4.2.4 SEO

  • 검색엔진에 페이지를 우선순위로 노출시키기 위해 개발자가 노력해야 하는 부분 알려줌

 

15.4.2.5 Progressive Web App(PWA)

  • 더 좋은 PWA이 되는 데 필요한 부분을 알려줌

 

출처

  • 이재성, 한정.  『기초부터 완성까지, 프런트엔드』. 서울: 비제이퍼블릭, 2021
  • Deepu K Sasidharan, "Visualizing memory management in V8 Engine (JavaScript, NodeJS, Deno, WebAssembly)
    ", Deepu K Sasidharan | Technorage , 2020-01-27, https://deepu.tech/memory-management-in-v8/