Image asset pre-load 전략

pengooseDev·2023년 2월 26일
0
post-thumbnail

헉! Background Image의 로딩이 늦어서 화면에 아무것도 안뜬다!

Carousel 컴포넌트를 만들던 도중 background Image가 미리 로드되어있지 않아 다음 image가 나올 때, 빈 화면이 rendering되는 현상을 확인했다.

물론, 0.1s 내외의 깨짐이기도 했고, 간단한 프로젝트라 그냥 넘어갈 수 있었지만, 이전부터 최적화라는 주제에 흥미가 많았기에 기회가 왔을 때 해결책을 고민해보고자 했다.


시도한 최적화 방법

1. 용량 줄이기

너무 당연한 이야기지만, 용량을 줄이면 더 빠르게 데이터를 가져올 수 있다.
사용하고 있는 image assets의 확장자를 webp로 바꾸어주자.

2. 웹 캐싱을 이용한 pre-load

웹 브라우저에 App 컴포넌트가 mount될 때, Carousel에 필요한 이미지를 미리 캐싱하는 전략을 사용할 수 있다.
Carousel의 assets이 자주 바뀌지 않으며, asset의 수가 많지 않기에 가능한 전략이었다.
image가 웹 브라우저에 캐싱되는 시점은 Image 객체의 src에 해당 assets이 할당되는 순간이다. 따라서, App 컴포넌트 내부에 useState를 이용해 캐싱해주는 전략이다.

forEach

import img1Src from './assets/img1'
import img2Src from './assets/img2'
import img3Src from './assets/img3'

myComponent() {
  	useEffect(()=>{},[
      [img1Src, img2Src, img3Src].forEach((v) => {
          const img = new Image();
          img.src = v;
      });
    ])
}


CSS를 이용한 해결책

public 정적파일을 CSS 가상 선택자를 이용한 content pre-load

public 폴더에 i3.webp 에셋 넣어두어야 한다.

import { createGlobalStyle } from 'styled-components';

const GlobalStyle = createGlobalStyle`
  /* PreLoad */
  body::after {
    content: url(i1.webp) url(i2.webp) url(i3.webp) url(i4.webp);
  }
`

물론, Global Style이 아닌, 해당 페이지의 Styled-components 내부에서 가상 선택자를 사용해 pre-load하는 방법도 있다.

해당 방법도 PromiseAll과 같은 병렬적 preLoad가 가능하다.


최종 결과

Image 객체를 이용해 forEach로 이미지 객체에 src를 할당하는 방식(힙 메모리 등록)을 채택해 초반 mount시점에서 병렬적으로 캐싱하였다.

image mount

200ms => 15ms~20ms

대략 1/10 가량의 시간을 줄임으로써 쾌적하고 아름다운 커스텀 carousel이 완성되었다!


추가적인 고민했던 solution

자동으로 Page가 변하는 Carousel이 아니라면 next나 prev 버튼에 hover했을 때, 해당 이미지를 불러오는 방법도 충분히 가능하다고 판단해보인다.

ref

0개의 댓글