프런트엔드 성능 최적화 (NHN Cloud 영상)

Sheryl Yun·2023년 7월 9일
0

영상 링크📷

원티드 7월 챌린지 디스코드에 올라온 최적화 영상을 보고 정리해보았다.


프런트엔드 성능 = 로딩 최적화 + 렌더링 최적화

유저가 겪는 성능 문제

공통점: '느리다'

  • 내용이 길면 느려져요
  • 스크롤이 툭툭 끊어져요
  • 로딩이 느려요
  • 때때로 화면이 멈춰요
  • 페이지 뜨는 데 몇 분씩 걸려요 ㅠㅠ

빠른 로딩 속도는 사업 지표와도 연결

상세 페이지 띄우는 데 20초, 결제 로딩하는 데 20초, ... => 이러면 X

성능 최적화
= 빠른 로딩 속도 → 사용성 개선 → 사업 지표 향상

예: Pinterest

  • 2019년 기준으로 월 이용자 수 2억 명의 큰 서비스였음
  • 이미지 페이지 띄우는 데 처음에 23초 걸림
    ⇒ 3개월에 걸쳐 성능 최적화
  • 결과
    • 사이트에 5분 이상 머무르는 사용자 수 40% 증가
    • 매출 44% 증가
    • 광고 수익 50% 증가 등등 사업 지표 향상

데모 예시: 개선 전 vs 개선 후

개선 전

  • 4초 가량 흰 화면 뜨고
  • 로딩 UI와 배경 화면 뜨고
  • 약 8초 만에 메인 컨텐츠(애니메이션) 등장
  • 애니메이션 렌더링 중에도 계속 툭툭 끊김

개선 후

  • 약 1초 만에 흰 화면이 떴다가 사라지고
  • 로딩 UI 등장
  • 전체 컨텐츠는 개선 전과 마찬가지로 8초 만에 뜨지만
  • 이후 끊김 없는 애니메이션 재생

로딩 최적화 🎿

1. 브라우저 기준 최적화

  • 브라우저에서 뜰 때의 과정
  • 앞쪽의 TCP/IP 부분(노란 박스)은 프론트가 최적화할 부분이 크게 없음
    • 뒤쪽 Processing과 Load 부분이 중요!

Processing

  • HTML, CSS, JS을 파싱하는 과정
  • Processing이 끝나면 DomContentLoaded 이벤트 발생
    • 브라우저가 어떤 것을 그릴 준비가 되었다는 것을 의미

Load

  • 렌더링에 필요한 파일(HTML에 포함된 이미지 등)을 로딩하는 과정
  • 로드가 끝나면 load 이벤트 발생

=> 브라우저 최적화란 이 두 이벤트의 시점을 최대한 앞당겨 빨리 일어나게 하는 것

데모 예시

  • 0초 ~ 4초
    • Processing 단계 (HTML, CSS, JS을 파싱하는 중)
    • 사용자에게는 흰 화면이 보임
  • 4초 ~ 8초
    • 이미지를 비롯한 모든 컨텐츠 로드(load)
    • 8초 이후(load 종료) 모든 컨텐츠가 화면에 나타남

흰 화면의 원인: 블록 리소스 (CSS, JS)

  • 블록 리소스
    • HTML 파싱을 멈추는 리소스 2가지: CSS, JS
    • CSS는 CSSOM 트리를 만들기 위함
    • JS는 DOM(HTML)에 접근하고 CSS를 변경할 수 있기 때문에
      • 브라우저의 입장에서는 JS가 접근하고 변경하는 과정에서 최악의 상황을 대비해 HTML 파싱을 멈추고 지금까지 만들어진 DOM과 CSSOM 트리를 준비해야 함
    • 이러한 블록 리소스들이 처리가 되기까지 계속 흰 화면 유지 (렌더링 X)

⇒ 브라우저에서의 최적화란 이 두 블록 리소스를 최적화하는 것

JS 로드 시점 최적화하기

= script 태그의 위치

  1. 아무 장치 없이 head 태그 내부 (x)
  2. body 태그 내부 하단 (o)
    • HTML이 모두 파싱되고 나서 JS가 실행될 수 있도록
  3. async, defer와 함께 head 태그 내부 (o)
    • 파싱을 하다가 JS를 만났을 때 async가 있으면 블록 리소스인 JS를 파싱하지 않고 계속 DOM 파싱을 진행 (= 렌더링이 막히지 않음)
      = async를 써서 ‘블록’되지 않게 할 수 있음

CSS 로드 시점 최적화하기

  • Waiting 시간 = TTFB (Time To First Byte)
    • 브라우저가 다운로드 요청 뒤 첫 byte를 받아서 처리하기까지 걸리는 시간
  • 최적화하는 법?
    • link 태그에서 .css 파일로 외부에서 불러오기 (X)
    • HTML 내부의 style 태그로 인라인 스타일로 적용
      - 다운로드 시간이 줄어들어 DomContentLoaded를 앞당김
      - DomContentLoaded를 앞당겨 흰 화면이 뜨는 시간과 로딩 UI 바 띄우는 시간을 2배 빠르게 함
      (개인적인 생각: 유지 보수 측면에서 좋은 방법은 아닌 듯 하다..)

브라우저 로딩 최적화의 문제점

  • 로딩 UI를 띄우는 것'만' 빨라짐
    = DomContentLoaded'만' 빨라짐
    - 흰 화면이 뜨는 시간이 줄어들 뿐 4초 대에 유의미한 컨텐츠가 나타나는 현상은 똑같다. (로드 완료도 마찬가지 => 8초 대로 동일)

사용자 기준 최적화 🥇

중요!

  • 이 최적화가 브라우저 최적화보다 더 중요함
  • 사용자가 중요하다고 느끼는 컨텐츠를 먼저 빠르게 보여줘야 한다.

이미지의 각 단계(노란색 글씨)별 구분

Is it happening?

  • First Paint
    • 흰 화면에서 처음으로 뭔가가 그려지기 시작하는 순간
  • First Contentful Paint
    • 화면에 처음으로 텍스트나 이미지가 그려지기 시작하는 순간

Is it useful?

  • First Meaningful Paint (FMP)
    • 유저에게 의미 있는 컨텐츠를 로드하는 순간
    • ** FE 최적화의 궁극적 목표: FMP 시점을 앞당기는 것!

Is it usable?

  • TTI (Time to interact)
    • 사용자가 화면과 인터랙션이 가능해진 순간

데모 예시

  • 로딩 UI가 뜬 시점 = First Paint
    • 브라우저 최적화를 통해 이 시점을 앞당길 수 있음
  • 유저에게 유의미한 컨텐츠가 뜬 시점= First Meaningful Paint (FMP)
    • 처음으로 배경 등의 컨텐츠 자료가 뜨기 시작한 4초 대
  • Time To Interact (TTI)
    • 컨텐츠가 완전히 로드되어 이벤트 동작까지 가능한 8초 대

>> 서버 사이드 렌더링 (SSR)

  • First Meaningful Paint(FMP)을 앞당기기 위한 방법 중 하나
    • 사용자에게 필요한(유의미한) 정보를 빠르게 보여주기 위함
  • SPA vs. SSR
    • Vue나 React의 SPA 개발
      • HTML, CSS 로딩 → 로딩 UI → AJAX로 왔다갔다 하며 필요한 정보 요청(JS) → 화면 로딩
      • 흰 화면이 나타나는 시간이 상대적으로 김
    • SSR
      • SPA에서 FCP 시점을 앞당기기 위해 쓰는 기술
      • 브라우저가 HTML을 요청하는 그 시점에 필요한 정보를 모두 로드해서 HTML을 생성해서 응답으로 내려보내고, 응답으로 받은 HTML을 브라우저가 화면에 로딩
      • 흰 화면 구간 거의 X

프리 렌더러와 SSR

  • 공통점
    • 둘 다 FMP를 위해 HTML과 CSS를 생성
  • 차이점
    • SSR은 서버에 브라우저가 요청하는 런타임 시점에 HTML과 CSS 생성
    • 프리 렌더러는 소스 빌드 타임에서 HTML, CSS 생성

PWA 사례

PWA = Web + App

  • 웹이 앱과 같은 성능을 가지도록 고안된 패턴
  • 신기술은 아니고 기존에 있던 기술들을 집약한 것

PRPL 패턴

Push / Render / Pre-cache / Lazy-load

예: 티켓 선택부터 결제까지 약 30초 안에 끝남

⇒ 로딩 성능은 사용자를 사로잡는 데 아주 중요한 역할

로딩 최적화 총 정리

2. 렌더링 최적화 🛫

레이아웃 스래싱

강제 동기 레이아웃이 빈번하게 발생하는 현상

강제 동기 레이아웃

  • 렌더링 시작 후 툭툭 끊기는 원인
  • 레이아웃을 변경하는 게 아닌 코드를 읽기만 해도 레이아웃 변경
    • 레이아웃 변경의 뜻 = DOM(HTML), CSS, Layout 변경이 모두 일어남
  • DOM 변경을 안 하고 '읽기'만 해도 스타일 계산을 새로 하고 레이아웃도 새로 만들어야 함
    • 여기서 '읽기'하는 대상 = 코드
  • 예:

  • offset 관련 코드: 매 애니메이션이 발생할 때마다 브라우저가 코드를 계속 읽음
    • 매번 강제 동기 레이아웃 발생
    • offset 프로퍼티를 읽는 순간 브라우저는 매번 최신 값을 계산하고 리턴하기 위해 레이아웃을 계속 다시 함

=> 렌더링 성능을 급격히 떨어뜨림

해결법

강제 동기 레이아웃이 발생하는 코드는 한 번만 쓰고 캐싱하기

캐싱만 해도 성능이 많이 개선됨 (렌더링 속도 엄청 빨라짐)

개선 전: 약 30fps 안팎 / 개선 후: 60fps (최적화 = fps 수치 높이기)

가상돔

  • 가상 돔에서 변경 사항 연산을 끝내고 레이아웃 변경이 일어나는 실제 돔에는 1번만 반영

웹 워커

  • 웹팩으로 기존 스레드에서 웹 워커 스레드로 옮기기
profile
데이터 분석가 준비 중입니다 (티스토리에 기록: https://cherylog.tistory.com/)

0개의 댓글