Carousel 컴포넌트를 만들던 도중 background Image가 미리 로드되어있지 않아 다음 image가 나올 때, 빈 화면이 rendering되는 현상을 확인했다.
물론, 0.1s 내외의 깨짐이기도 했고, 간단한 프로젝트라 그냥 넘어갈 수 있었지만, 이전부터 최적화라는 주제에 흥미가 많았기에 기회가 왔을 때 해결책을 고민해보고자 했다.
너무 당연한 이야기지만, 용량을 줄이면 더 빠르게 데이터를 가져올 수 있다.
사용하고 있는 image assets의 확장자를 webp로 바꾸어주자.
웹 브라우저에 App 컴포넌트가 mount될 때, Carousel에 필요한 이미지를 미리 캐싱하는 전략을 사용할 수 있다.
Carousel의 assets이 자주 바뀌지 않으며, asset의 수가 많지 않기에 가능한 전략이었다.
image가 웹 브라우저에 캐싱되는 시점은 Image 객체의 src에 해당 assets이 할당되는 순간이다. 따라서, App 컴포넌트 내부에 useState를 이용해 캐싱해주는 전략이다.
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;
});
])
}
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시점에서 병렬적으로 캐싱하였다.
200ms => 15ms~20ms
대략 1/10 가량의 시간을 줄임으로써 쾌적하고 아름다운 커스텀 carousel이 완성되었다!
자동으로 Page가 변하는 Carousel이 아니라면 next나 prev 버튼에 hover했을 때, 해당 이미지를 불러오는 방법도 충분히 가능하다고 판단해보인다.