[딜리버블] ← 해당 프로젝트에 적용한 내용입니다. 

 

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 대신 setTimeoutstartTime, endTime을 이용하면 렌더링을 문장의 개수만큼만 발생시킬 수 있을 것 같다는 생각이 들었습니다. 

 

endTime에서 startTime을 뺀 시간은 특정 문장을 아나운서가 읽는데 걸리는 총 시간입니다. 이 시간을 setTimeout의 딜레이로 설정하고 콜백 함수에서 현재 문장의 인덱스를 증가시키면 아나운서가 문장을 다 읽었을 때(= 딜레이가 끝났을 때) 다음 문장의 인덱스 정보를 가지게 됩니다. 

 

이 로직의 구현을 위해서 currentTime 상태 대신 아나운서가 현재 말하고 있는 문장의 인덱스 정보를 저장하는 currentSentenceIndex 상태를 새로 만들었습니다. const [currentSentenceIndex, setCurrentSentenceIndex] = useState(0);

 

이제 사용자가 처음으로 동영상 재생을 눌렀다고 가정한다면(videoState 변경) 첫 번째 문장의 endTimestartTime을 뺀 시간, 즉 첫 번째 문장을 아나운서가 읽는 시간이 지나고 나서 문장의 인덱스가 증가합니다. 

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으로 설정하여 첫 번째 문장이 파란색이 되도록 하였습니다. 

 

아까와 동일하게 아나운서가 두 번째 문장을 말하기 시작하는 지점까지 프로파일링을 해보겠습니다. 

이전과는 다르게 동영상 재생 중에 렌더링이 계속해서 일어나지 않고 문장이 바뀔 때만발생하는 것을 확인할 수 있습니다. 

 

복사했습니다!