[딜리버블] ← 해당 프로젝트에 적용한 내용입니다.
Profiler를 통해 성능 측정
React Developer Tools의 Profiler로 애플리케이션이 렌더링될 때마다 자동으로 성능 정보를 수집할 수 있습니다. 성능을 측정하고자 하는 부분을 녹화한 후 중지를 누르면 컴포넌트별 렌더링 여부와 렌더링 시간 등을 볼 수 있습니다.
Profiler는 커밋별로 성능 정보를 그룹화합니다. 커밋은 프로파일러 상단 근처의 막대형 차트에 표시됩니다. 바의 색상과 높이는 렌더링에 걸린 시간을 의미합니다. 이 도구를 통해서 불필요한 렌더링을 줄이고 최적화를 할 수 있습니다.
동영상 재생시 렌더링 최적화
학습 상세 페이지에서 스크립트의 두 번째 문장 시작 지점까지 동영상을 재생하는 동작을 프로파일링 한 결과입니다. 10초도 안되는 시간동안 렌더링이 68번이나 일어난 것을 볼 수 있습니다.
이렇게 많은 렌더링은 아나운서가 말하고 있는 문장을 파란 색상으로 강조하는 로직으로 인해 발생하고 있었습니다.
videoData.sentences.map(({ id, order, text, startTime, endTime }, i) => (
<StScriptText
...
onClick={() => player?.seekTo(startTime, true)}
isActive={startTime <= currentTime && currentTime < endTime}>
...
</StScriptText>
))
여기서 currentTime
은 상태입니다. const [currentTime, setCurrentTime] = useState(0);
useEffect(() => {
if (!player) return;
const interval =
player &&
setInterval(() => {
setCurrentTime(player.getCurrentTime());
}, 100);
if (videoState === VIDEO_STATE_PAUSED || videoState === VIDEO_STATE_CUED) {
interval && clearInterval(interval);
}
return () => interval && clearInterval(interval);
}, [player, videoState]);
videoState
는 동영상 플레이어의 상태(재생, 일지정지, 버퍼링 등)를 저장하는 상태입니다.
videoState
가 변경이 되면 setInterval
을 통해 100ms마다 currentTime
을 동영상 재생이 시작된 이후의 경과 시간으로 설정하고 있습니다. 그리고 이렇게 설정한 currentTime
이 스크립트 문장의 startTime
이상이거나 endTime
미만이면 문장 색을 파란색으로 설정하는 로직입니다.
100ms마다 currentTime
상태를 재설정하고 있으므로 컴포넌트도 그때마다 리렌더링되고 있습니다.
렌더링을 줄이기 위해 로직을 개선하는 것이 필요하다고 판단하였습니다.
일정한 시간 간격을 두고 반복 실행하는 setInterval
대신 setTimeout
과 startTime
, endTime
을 이용하면 렌더링을 문장의 개수만큼만 발생시킬 수 있을 것 같다는 생각이 들었습니다.
endTime
에서 startTime
을 뺀 시간은 특정 문장을 아나운서가 읽는데 걸리는 총 시간입니다. 이 시간을 setTimeout
의 딜레이로 설정하고 콜백 함수에서 현재 문장의 인덱스를 증가시키면 아나운서가 문장을 다 읽었을 때(= 딜레이가 끝났을 때) 다음 문장의 인덱스 정보를 가지게 됩니다.
이 로직의 구현을 위해서 currentTime
상태 대신 아나운서가 현재 말하고 있는 문장의 인덱스 정보를 저장하는 currentSentenceIndex
상태를 새로 만들었습니다. const [currentSentenceIndex, setCurrentSentenceIndex] = useState(0);
이제 사용자가 처음으로 동영상 재생을 눌렀다고 가정한다면(videoState
변경) 첫 번째 문장의 endTime
과 startTime
을 뺀 시간, 즉 첫 번째 문장을 아나운서가 읽는 시간이 지나고 나서 문장의 인덱스가 증가합니다.
useEffect(() => {
if (!videoData) return;
if (currentSentenceIndex >= videoData.sentences.length) {
setCurrentSentenceIndex(0);
return;
}
if (videoState === VIDEO_STATE_PLAYING) {
const currentSentence = videoData.sentences[currentSentenceIndex];
const delay = (currentSentence.endTime - currentSentence.startTime) * 1000;
const timeoutId = setTimeout(() => setCurrentSentenceIndex((prev) => prev + 1), delay);
return () => timeoutId && clearTimeout(timeoutId);
}
}, [currentSentenceIndex, videoData, videoState]);
이제 isActive 로직을 isActive={i === currentSentenceIndex}
로 설정한다면 현재 아나운서가 말하고 있는 부분의 문장 색이 파란색이 될 것입니다.
추가로 동영상 재생이 끝나면 다시 처음부터 재생이 되기 대문에 현재 문장의 인덱스가 총 문장 개수와 같아지면 currentSentenceIndex
를 다시 0으로 설정하여 첫 번째 문장이 파란색이 되도록 하였습니다.
아까와 동일하게 아나운서가 두 번째 문장을 말하기 시작하는 지점까지 프로파일링을 해보겠습니다.
이전과는 다르게 동영상 재생 중에 렌더링이 계속해서 일어나지 않고 문장이 바뀔 때만발생하는 것을 확인할 수 있습니다.
'프로그래밍 > Next' 카테고리의 다른 글
Open AI 사용해보기 (with Edge Function) (1) | 2023.08.10 |
---|---|
[성능 개선] Next.js 프로젝트 LCP 최적화하기 (0) | 2023.05.11 |
캐싱, Cache-Control 알아보기 🥹 (0) | 2023.02.01 |
[Next] Dynamic Routes / Router Hook / Catch All (0) | 2022.07.08 |
[Next] Patterns / Fetching Data / Redirect & Rewrite / SSR (0) | 2022.07.08 |