zero-wiki Help

올림픽 통계 서비스 최적화

애니메이션 최적화

문제의 코드

const BarGraph = styled.div` position: absolute; left: 0; top: 0; width: ${({width}) => width}%; transition: width 1.5s ease; height: 100%; background: ${({isSelected}) => isSelected ? 'rgba(126, 198, 81, 0.7)' : 'rgb(198, 198, 198)'}; z-index: 1; `

width에 맞게 그래프가 그려지고 있는데 변화하는 것을 화면이 60FPS로 보여주지 못하기 때문에 뚝뚝 끊기는 것으로 보입니다.

브라우저 렌더링 과정

브라우저는 다음과 같은 렌더링 과정을 거칩니다.

  1. DOM + CSSOM

  2. 렌더 트리

  3. 레이아웃

  4. 페인트

  5. 컴포지트

1. DOM + CSSOM

HTML 파일과 CSS 등 화면을 그리는데 필요한 리소스를 다운로드 받아 브라우저가 이해할 수 있는 형태로 만드는 파싱과정을 거칩니다. 변환 결과, DOM과 CSSOM이라는 트리구조가 생성됩니다.

2. 렌더 트리

DOM과 CSSOM의 결합으로 생성됩니다. 화면에 표시될 요소의 레이아웃 계산에 사용됩니다. display: none과 같은 설정의 경우 렌더 트리에 포함되지 않습니다.

3. 레이아웃

화면 구성 요소의 위치나 크기를 계산하고, 해당 위치에 요소를 배치하는 작업을 진행합니다.

4. 페인트

요소에 색을 채워넣는 작업을 진행합니다. 배경 색, 글자 색, 테두리 색을 추가합니다. 레이어를 분리해서 작업하기도 합니다.

5. 컴포지트

완성된 레이어들을 하나로 형성하는 작업을 진행합니다.

이러한 과정들을 Performance 패널에서 확인할 수 있습니다.

렌더링 작업.png

또한 사람에게 보여지는 화면이 그려지는 위치는 점선이 그려지는 시점입니다.

변경되는 과정, 리플로우, 리페인트

만약 요소의 width나 height가 변경되었다고 하였을 때 브라우저의 가로, 세로 요소를 다시 계산하여야 합니다. 이럴 경우 처음부터 다시 고려하여 그려져야 하는데 이런 과정을 리플로우라고 합니다.

이와 다르게 색상 관련 속성이 바뀔 경우 DOM + CSSOM 등을 처음부터 계산하지 않고 페인트와 컴포지트의 순서만 진행하는 경우도 있습니다.

하드웨어 가속(GPU 가속)

하드웨어 가속은 CPU에서 할 작업을 GPU에 위임하여 효율적으로 처리하는 방법을 말합니다. GPU는 애초에 그래픽 작업을 처리하기 위해 만들어진 것이므로 화면을 그릴 때 굉장히 빠릅니다.

특정 요소에 하드웨어 가속을 사용하려면 요소를 별도의 레이어로 분리하여 GPU로 보내야 하는데, transform 속성과 opacity 속성이 이러한 역할을 합니다. 분리된 레이어는 GPU에 의해 처리되므로 레이아웃 단계나 페인트 단계 없이 요소의 스타일을 변경할 수 있습니다.

변경 전

const BarGraph = styled.div` position: absolute; left: 0; top: 0; width: ${({width}) => width}%; transition: width 1.5s ease; height: 100%; background: ${({isSelected}) => isSelected ? 'rgba(126, 198, 81, 0.7)' : 'rgb(198, 198, 198)'}; z-index: 1; `

변경 후

const BarGraph = styled.div` position: absolute; left: 0; top: 0; width: 100%; transform: scaleX(${({ width }) => width / 100}); transform-origin: center left; transition: transform 1.5s ease; height: 100%; background: ${({ isSelected }) => isSelected ? "rgba(126, 198, 81, 0.7)" : "rgb(198, 198, 198)"}; z-index: 1; `;

컴포넌트 지연 로딩

modal 내에서 image-gallery 라이브러리를 사용하기 때문에 초기 렌더링 시 많은 코드를 한 번에 불러오고 있습니다.

때문에 lazy 로딩을 이용하여 천천히 불러오도록 합니다.

컴포넌트 사전 로딩

지연 로딩의 단점

모달을 지연 로딩으로 분리하면 초기 로딩시에는 속도를 단축시킬 수 있지만, 이후에 띄우는 경우 한계가 분명히 있을 수 있습니다.

컴포넌트 사전 로딩

모달에서 컴포넌트가 필요한 위치는 버튼을 클릭하는 시점입니다. 만약 사용자가 버튼을 클릭하기 전에 미리 모달 코드를 로드를 한다면 시간을 단축할 수 있어 빠르게 모달을 띄울 수 있습니다.

컴포넌트 사전 로딩 타이밍

다음과 같이 미리 로드하는 함수를 만들어서 사용할 수 있습니다.

const LazyImageModal = lazy(() => import("./components/ImageModal")); const Component = () => { const handleMouseEnter = () => { const preload = () => import("./components/ImageModal"); preload(); }; return ( <button onClick={() => { setShowModal(true); }} onMouseEnter={handleMouseEnter} > 모달 열기 </button> ) }

이미지 사전 로딩

앞서 컴포넌트와 달리 이미지는 HTML 또는 CSS에서 이미지를 사용하는 시점에 로드됩니다.

이외에도 자바스크립트로 이미지를 직접 로드할 수 있습니다. 바로 자바스크립트의 image 객체를 사용하면 됩니다.

const img = new Image(); img.src = `{이미지 주소}`

이미지가 사전 로딩이 가능한 이유는 이미지를 로드할 때 브라우저가 해당 이미지를 캐싱해 두기 때문입니다. 만약 disable cache 옵션이 체크되어 있으면 이미지 리소스에 대해 캐시를 하지 않아 매번 새로 불러옵니다.

또한 사전 로딩을 할 경우, 어디까지 사전 로딩을 할 것인지, 정말 사전 로딩이 필요한지 고민을 해야합니다.

브라우저의 캐시 상태를 고려하여 캐시하는 방법

function App() { const [showModal, setShowModal] = useState(false); const handleMouseEnter = () => { // 브라우저가 캐시를 지원하는지 확인 const isCacheSupported = 'caches' in window; if (isCacheSupported) { const prefetch = () => import("./components/ImageModal"); prefetch().catch(() => {}); } else { console.log('브라우저 캐시가 비활성화되어 있어 사전 로딩을 건너뜁니다.'); } }; return ( // ... existing code ... ); }

구체적으로 캐시 정책을 활용하고 싶다면

function App() { const [showModal, setShowModal] = useState(false); const checkCacheStatus = async () => { try { // 캐시 스토리지 접근 가능 여부 확인 const cache = await caches.open('image-cache'); return true; } catch { return false; } }; const handleMouseEnter = async () => { const isCacheAvailable = await checkCacheStatus(); if (isCacheAvailable) { const prefetch = () => import("./components/ImageModal"); prefetch().catch(() => {}); } else { console.log('캐시를 사용할 수 없어 사전 로딩을 건너뜁니다.'); } }; return ( // ... existing code ... ); }
Last modified: 08 November 2024