이 프로젝트는 불가피하게 고화질의 gif, png 등을 사용하게 되었다.
이러한 소스들은 무거울수록 사용자 경험 측면에서 비효율적이기 때문에, 이를 개선한 과정과 고민에 대해 글로 작성하려 한다.
고화질 소스들은 그냥 사용했을 때 렌더링 시 뚝 끊기는 현상이 발생됐고, 이는 사용자 경험 측면에서 비효율적이라 판단했다.
과연 어떤 이유로 뚝 끊기는 현상이 발생했을까?
먼저 브라우져 렌더링은 아래와 같다.
웹은 기본적으로 동기화(Synchronos) 속성을 갖고 있기 때문에 HTML렌더링 하는 과정에서 HTML태그 등에서 src atrribute 가 사용된다면 즉시 파싱을 멈추고 브라우저는 해당 소스를 가져오게 된다.
해결법은 js 상에서 소스가 무거운 gif 파일을 미리 프리로딩을 하여 미리 소스를 불러오면 된다.
HTML 렌더링이 끝난 후 미리 로드한 gif 파일을 동기적으로 가져오게 된다면 재렌더링이 되므로 로딩을 만들어 로딩 동안 파일을 전부 불러오게 만들었다.
이렇게 된다면 끊기지 않고 유저 친화적으로 이미지 프리로딩을 적용할 수 있다.
먼저 기본적인 프리로딩 소스 코드이다.
/*const images = [
"http://example.com/image1.png",
"http://example.com/image2.png",
"http://example.com/image3.png"
]; */
const preload = (images) => () => {
images.forEach((image) => {
const img = new Image();
img.src = image;
});
};
이미지가 로딩되고 나서 추가적인 작업 사항이 있다면, 이미지 자체에 onload, onerror를 추가적으로 걸 수 있다.
위 코드를 리액트로 적용하면 다음과 같다.
const gif = [............]
const preLoadGif = useCallback(() => {
const loadImg= gif.map((url) => {
return new Promise((resolve) => {
const img = new Image()
img.onload = () => resolve()
img.src = url
})
})
return Promise.all(loadImg)
}, [gif])
useEffect(() => {
const preLoad = async () => await preLoadGif()
preLoad()
// 로딩 종료
}, [preLoadGif])
이렇게 받아온 이미지 소스들은 개발자도구 > 퍼포먼스 탭에서 확인 가능하다.
<프리로딩 적용 전>
<프리로딩 적용 후>
각각 비교해 보면 프리로딩 전과 후의 로드되는 시점이 다르다는 것을 확인할 수 있다.
만약 무거운 소스들을 사용자 경험을 고려하여 설계를 하고 있다면 이미지 프리로딩을 적용해 보는 것을 추천한다.
만약 고화질의 소스들이 다수 있다면 로딩 스패너를 만들어 구현해 보자.