TIL 111. 2024-06-07

이준구·2024년 8월 14일
0

TIL 순서

목록 보기
113/119
post-thumbnail

두 번째 해결방안)

  • 서버 시간과 클라이언트 시간의 Gap 차이를 구하여 타이머 실행 및 모달창 종료

1-1) 실제 클라이언트와 서버 간의 밀리초 단위의 시간 차가 존재

  • 아래의 사진은 초 단위로 변경하기 전의 getTime() 메서드 형식의 시간
  • Gap: 0.001 ~ 0.005s

Gap 구하는 방법

  • 서버시간
  • 클라이언트 시간
  • gap: 서버 시간 - 클라이언트 시간
  • 게임 타이머: 전달받은 타이머 + Gap

1-2) 코드 해석
: 모달창 겹치는 현상이 발생하는 socket Event: "showModal" 부분에서 Gap을 더한 타이머를 해당 ModalProgress의 setState값에 전달

  const sockets = {
    showModal: (title: string, timer: number, serverTime: any) => {
      //클라이언트 시간
      const clientTime = new Date();
      //gap: 서버 시간- 클라이언트 시간
      const timeGap = serverTime - clientTime.getTime();
      // gap을 초단위로 변경
      const timeGapSeconds = timeGap / 1000;
      // 게임 타이머: 전달받은 타이머 + Gap
      const gameTime = timer + timeGapSeconds;
      
      //타이머 전달
      setTime(gameTime)
    }
}

1-3) ModalProgress 컴포넌트 코드 해석

  • 위의 Gap을 더한 timer의 단위가 ms단위이므로 useCountDown 부분의 dely값 또한, ms 단위로 쪼개어 실행
const ModalProgress = () => {
  const isModal = useModalIsOpen();
  const timer = useModalTimer();
  const [count, setCount] = useState(timer * 1000); //ms 단위

  const { setIsOpen } = useModalActions();

  //NOTE - 타이머 기능
  useCountDown(() => setCount((prevCount) => prevCount - 1), 1, isModal);

 // 0같거나 작을 경우 -> 모달창 종료
  useEffect(() => {
    if (count <= 0 && isModal) {
      setIsOpen(false);
    }
  }, [count]);

return(
  <progress className={S.progress} value={(timer * 10 - count) * (100 / (timer * 10))} max={90}></progress>
  )
};

1-3) useCountDown 컴포넌트 코드 해석

  • 매개변수: setCount((prevCount) => prevCount - 1), 1, isModal
export const useCountDown = (callback: () => void, delay: number, isCount: boolean) => {
  const savedCallback = useRef<() => void>(callback);

  useEffect(() => {
    if (!isCount || !delay) {
      return;
    }

    //현재 저장된 콜백 함수 호출
    const tick = () => {
      savedCallback.current();
    };

    const timerId = setInterval(tick, delay);

    return () => {
      clearInterval(timerId);
    };
  }, [isCount]);
};

두 번째 결과)

두 번째 방법으로 문제가 해결되지 않은 이유에 대한 생각

  • setInterval의 delay를 1ms 단위로 countDown 실행 시 정상 작동되지 않는 걸 확인할 수 있었다. MDN 문서를 통해 알게된 "브라우저에서 자체적으로 delay 최소값인 시간 간격을 4ms 적용"이 원인이었다.

  • 현재 서버와 클라이언트 간의 시간 차이로 인해 발생하는 문제는 단순히 소켓 이벤트 전송 시에만 발생하는 것이 아니라, 서버와 클라이언트에서 각각 실행되는 setInterval 시간의 불일치로 인해 발생한다고 판단

setInterval 함수의 비동기성 및 Web API: setInterval 함수는 비동기적으로 동작하는 Web API 함수입니다. 자바스크립트는 싱글 스레드 환경에서 작동하기 때문에 한 번에 하나의 명령만 처리할 수 있습니다.
이벤트 루프와 태스크 큐: setInterval 함수는 지정된 간격마다 콜백 함수를 태스크 큐에 추가합니다. 이벤트 루프는 콜 스택이 비어 있을 때 태스크 큐에서 작업을 가져와 실행합니다. 따라서 기존 명령이 실행 중인 경우, setInterval로 추가된 콜백 함수는 대기해야 합니다.
정확한 시간 보장 어려움: 이러한 구조로 인해 클라이언트 측의 setInterval 함수는 정확한 시간 간격을 보장하기 어렵습니다. 이벤트 루프가 바쁘거나 다른 작업이 실행 중이면 지연이 발생할 수 있습니다.
클라이언트와 서버 간의 동기화 문제: 클라이언트와 서버에서 각각 setInterval을 사용하면 두 환경의 타이머가 정확하게 일치하지 않을 가능성이 큽니다. 클라이언트와 서버의 작업 부하, 네트워크 지연, 이벤트 루프 상태 등 여러 요인으로 인해 타이머의 동기화가 어렵습니다.



profile
개발 중~~~ 내 자신도 발전 중😂🤣

0개의 댓글

관련 채용 정보