강연 링크: https://www.youtube.com/watch?v=G1IWq2blu8c
강연 요약
강연 정리 노트
프론트엔드 성능 최적화 설명
로딩 최적화: 브라우저
브라우저는 HTML을 parsing(분석) 함 → HTML 분석 완료 후, domContentLoadedEvent 이벤트 발생 → domContentLoadedEvent 완료 후, loadEvent 이벤트 발생
순서: HTML parsing → domContentLoadedEvent → loadEvent
domContentLoadedEvent: HTML 문서를 완전히 불러오고 분석했을 때 발생하는 이벤트 (스타일 시트, 이미지 등의 로딩은 포함 안됨)
loadEvent: HTML이 포함하고 있는 자바스크립트, 스타일 시트, 이미지 등 리소스까지 모두 로드되었을 때 발생하는 이벤트
브라우저 로딩 최적화는 이 2가지 이벤트 시점을 앞당기고 빠르게 하는 것이 목표 (domContentLoadedEvent, loadEvent)
로딩 과정에서 흰 화면이 지속되면 답답함을 줄 수 있음
브라우저는 HTML, CSS, JavaScript를 각각 파싱
HTML 파싱을 하다가 CSS를 만나면 HTML 파싱을 멈추고 CSS, JavaScript 파싱을 수행
HTML 파싱을 멈추는 이 CSS, JavaScript 리소스들을 '블록 리소스' 라고 부름
블록 리소스 때문에 HTML 파싱을 멈춰서 브라우저에 계속 흰 화면이 나오는 것
브라우저 렌더링 과정: HTML 파싱해서 DOM Tree를 만듦 + 스타일 정보 파싱해서 CSSOM Tree를 만듦 → DOM Tree, CSSOM Tree 이 두 Tree로 Render Tree를 만듦 → Render Tree를 가지고 layout 과정을 거치게 됨 (layout 과정: 각 요소들의 위치와 크기를 계산하는 과정) → painting 과정(화면에 뿌려주는 과정)
블록 리소스: 자바스크립트, 스타일
흰 화면 지속 시간을 줄이기 위해 블록 리소스 처리 최적화 필요
블록 리소스 처리 최적화 = 자바스크립트 로드 시점 최적화 + 스타일 로드 시점 최적화
자바스크릡트 로드 시점 최적화
script 태그는 자바스크립트를 실행함으로 HTML 파싱을 잠시 멈추는 블록 리소스 임
script 태그가 head 태그에 있으면 밑에 있는 HTML들은 파싱되기도 전에 파싱을 잠시 멈춤 → 흰 화면 지속 → 이러한 상황을 방지하기 위해 script 태그를 보통 body 태그 하단에 위치시킴, 혹은 head 태그에 위치시키면서 script 태그에 async나 defer를 사용
브라우저는 HTML 파싱 중 async를 만나면 블록을 시키지 않고 HTML 파싱을 지속함 → async를 사용하면 HTML 파싱이 블록되지 않기 때문에 DOMContentLoaded 시간을 단축시킬 수 있음
스타일 로드 시점 최적화
브라우저가 CSS 다운로드 요청(Request sent)을 하고 다운로드를 하기까지 Waiting 시간이 있음(TTFB: 첫 바이트를 받아서 처리하기까지 걸리는 시간) → 요청 후 waiting 시간을 줄임으로 최적화
Waiting 시간 개선 방법 → HTML 파일에 스타일을 inline으로 직접 포함 시킴 (CSS 다운로드 요청 줄임으로써 Waiting 타임을 없앨 수 있음) → DOMContentLoaded 시간을 단축시킬 수 있음
요약
브라우저 로딩 최적화 방법은 DOMContentLoaded 단축
방법1: 자바스크립트 async, defer 사용
방법2: 인라인 스타일 사용
브라우저 로딩 최적화 한계점: DOMContentLoaded 를 앞당겨도 DOMContentLoaded는 이미지 등 다른 리소스 로드를 포함하지 않기 때문에 크게 성능 변화를 느끼지 못 할 수 있음 → 따라서 사용자 기준의 최적화가 더 중요
로딩 최적화: 사용자 기준
사용자 기준 로딩 최적화의 핵심은 First Meaningful Paint 시점을 앞당기는 것
First Paint: 빈 화면에 처음으로 무언가 그려지는 순간
First Contentful Paint: 처음으로 텍스트나 이미지가 표현되는 순간
First Meaningful Paint: 처음으로 사용자에게 의미있는 콘텐츠를 로딩하는 순간 (의미있는 콘텐츠 기준은 아직 모호, 개발자 주관적 기준)
Time to interactive: 모든 리소스가 로딩되서 사용자와 인터렉션 할 수 있는 순간
SPA(React, Vue, Angular frameworks)에서 First Meaningful Paint 시점을 앞당기는 방법 → 서버 사이드 렌더링, 프리 렌더링
서버 사이드 렌더링, 프리 렌더링 방식 모두 First Meaningful Paint를 하기 위해 HTML, CSS 를 생성
프리 렌더링: 빌드 타임에 HTML, CSS를 생성
서버 사이드 렌더링 방식의 HTML, CSS 생성 시점 → 서버 런타임 (서버 쪽에 요청 온 시점)
프리 렌더링 방식의 HTML, CSS 생성 시점 → 소스 빌드 타임
Webpack을 번들러로 사용한다면 Webpack에서 프리 렌더링 방식을 적용 할 수 있는 도구: prerender-loader
prerender-loader 사용시 빌드 타임에 컨텐츠를 만들어 내서 First Meaningful Paint를 앞 당길 수 있음
DomContentLoad 완료되기 전 paint를 할 수 있음 → HTML 컨텐츠가 약간 늘어나지만 훨씬 효과적
사용자 기준에서 의미 있는 First Meaningful Paint 시점을 앞 당겼다면 DOMContentLoaded 속도는 덜 중요 할 수 있음
요약
사용자에게 의미있는 콘텐츠를 로딩하는 순간을 앞당기는 것으로 사용자 기준 로딩 최적화를 할 수 있다
방법1 : 서버 사이드 렌더링
방법2 : 프리 렌더링 → Webpack을 bundler로 사용 시 prerender-loader 사용
로딩 성능 최적화: PWA
렌더링 최적화: 레이아웃 스래싱 줄이기
Layout 과정: HTML, CSS를 파싱해서 요소의 위치 크기를 계산하는 작업, 비용이 상대적으로 크고 오래걸림
Paint 과정: 화면에 뿌리는 작업
자바스크립트 DOM 조작 시 변경사항이 생겼음으로 Layout → Paint 과정이 다시 발생
강제 동기 레이아웃: DOM을 변경하지 않았음에도 Layout → Paint 과정을 발생시킴
어떠한 DOM Element는 읽기만해도 강제 동기 레이아웃 과정이 발생 (예: let offsetLeft = this.element.offsetLeft;) → 이러한 DOM을 읽을 때마다 Layout 과정 발생이 빈번히 발생 → 캐싱으로 개선 시 강제 동기 레이아웃 발생을 줄여 성능 많이 개선됨
강제 동기 레이아웃이 매우 빈번하게 발생 하는 것을 레이아웃 스래싱이라고 함 → 렌더링 성능을 많이 떨어트리는 원인
요약
DOM element를 읽는 것을 캐싱으로 줄여서 레이아웃 과정 발생 빈도를 줄이자
렌더링 최적화: 가상돔
렌더링 최적화: 웹 워커