브라우저는 일반적으로 아래의 순서대로 렌더링한다.
- html 파싱 (위에서 아래로 head -> body) :
1. HTML 파싱 및 DOM 생성
2. CSS 파일 로드 및 적용 (렌더링 차단)
3. 스크립트 로드 및 실행 (렌더링 차단)
4. <body> 섹션의 내용 렌더링 (이미지, 텍스트 등)
브라우저의 리소스 우선순위를 제어하면 페이지 로딩 속도를 최적화할 수 있다.
아래의 렌더링 순서를 개선할 수 있는 아래의 주요 속성들을 기록하고자 한다.
- JavaScript: async, defer, module
- CSS: preload, media
- 이미지: loading="lazy", srcset, sizes
- 기타: prefetch, preconnect, dns-prefetch
JavaScript
async : html 파싱과 병렬로 다운로드되고, 다운로드 후 즉시 실행된다. 페이지의 어떤 리소스가 이 js와 관련이 있다면 async 태그는 빼는 것이 좋다.
defer : html 파싱과 병렬로 다운로드되고, html 파싱이 완전히 끝난 다음에 실행된다. = 순서가 보장된다. html이 모두 렌더링된 다음에 실행해야 한다면 defer 태그를 추가하는 것이 좋다.
브라우저는 기본적으로 html을 먼저 load하는데, 만약 head 태그 내에 script 소스가 있다면 렌더링이 차단된다. 위 두 태그를 추가하면 html 렌더링 차단을 막을 수 있다.
CSS
styleshee : 기본값이다. 렌더링을 차단하는 요소이며, 반드시 css가 로드되어야 하는 경우 사용한다.
preload : 렌더링을 차단하지 않고 미리 다운로드한다. onload 이벤트 발생 시점에 stylesheet로 변경되어 스타일이 적용된다.
media: 화면 크기 조건에 맞을 경우 렌더링한다.
이미지
loading="lazy" : 이미지가 화면에 나타날 때 로딩한다. (스크롤의 위치가 이미지가 위치한 요소 근처일 때)
srcset : 화면 크기에 맞는 최적의 이미지를 선택한다. (이미지 용량 최적화)
sizes : 브라우저가 뷰포트 크기에 따라 적합한 이미지를 선택하도록 힌트를 제공한다.
마지막 img 태그의 경우 width가 480px인 이미지, 1024px인 이미지가 있을 때, size 속성에 의해 max-width가 600px이면 480px짜리 이미지를, 그 외에는 1024px 이미지를 나타내도록 한다.
* 커머스에서는 한 페이지 안에 이미지가 수십개에 달하므로, 이미지 용량을 줄이면 효과가 크다.
예를들어, 검색결과 화면에는 최소 20개 이상의 이미지가 있고, 검색이 하루에 100,000번 실행된다면...
기타
rel="prefetch": 페이지를 이동하기 전에 미리 리소스를 다운하여 다음 페이지에서의 로딩속도를 개선한다.
rel="preconnect": 특정 링크에 대한 네트워크 연결을 미리 설정한다. (크기가 큰 비디오, 폰트 등)
rel="dns-prefetch": 외부 리소스의 dns를 조회하여 리소스를 더 빠르게 로드한다. (주로 외부 CDN)
* preconnect vs dns-prefetch
preconnect는 tcp 연결(dns - tcp handshake - tls handshake)이므로, 브라우저 리소스를 잡고 있는 무거운 동작이다. 외부 리소스를 빨리 로드해야 할 때 사용한다. (아주 중요한 리소스이고 이 리소스의 빠른 렌더링이 중요할 때)
dns-prefetch는 dns만 조회하기 때문에 더 가벼운 동작이다. 중요하지 않은 리소스이고 추후에 불러올 때 적합하다.