회사에서 타이머 관련 부분에서 에러가 생겼다.

간략하게 버그를 적어보면,
setInterval 안에서 실행되는 callback 함수가 clearInterval 되어도 실행되기 때문에 생긴 버그다.

어찌보면 당연한 일이다.

clearInterval 되었다고 이미 콜 스택에 쌓인 함수는 실행 될 것이기 때문이니깐.

여러가지 실험을 해서 알게된 사실을 적어보면 다음과 같다.


  1. setInterval은 정확한 타이밍에 실행된다고 보장할 수 없다.
    • 두번째 인자인 시간에 100ms 뒤에 실행된다고 선언 해놓아도, 정확히 100ms 마다 실행된다고 보장 할 수 없다. (100ms, 204ms, 306ms, 401ms, 507ms 마다 실행될 수 있다.)
    • setInterval 은 해당 시간만큼 browser의 타이머에 의해 시간을 보내고 콜스택에 들어가게 된다. 이미 실행중인 함수가 있다면 해당함수 뒤에 쌓일뿐이다.
  1. setInterval 내부의 콜백함수에서 비동기 작업을 하고 clear 시킨다면?

    • setInterval 은 100ms 마다 setTimeout 을 실행한다.
    • setTimeout 은 1000ms 후에 console.log 를 찍는다
    • 약 5초 후에 clearInterval 을 시킨다.
  • 결과를 보면, clearInterval 이 되고난 뒤에 setTimeout 에 의한 console.log는 여전히 찍히게 된다. 여기서 생각난 말은 일어날 일은 일어난다. 이다.

    만약, setIntervalcallBack 함수가 100ms 마다 , 예시로든 1초가 걸리는 setTimeout 이 아니라, ajax 통신 요청을 하고 있다면..??
    예를들어, 콜 스택에 등록된 50번의 ajax 통신 중에 30번 째에서 통신에 성공하여 response 에 의해 상태값이 변경되어, clearInterval 을 시켰다. 그렇다고 해도 20번의 ajax 통신은 실행될 수 밖에 없다.

  1. 어떻게 남은 20번의 callBack 함수를 실행 안시킨것 처럼 할 수 있을까?
    제가 선택한 간단하고 명확한 답은 실행할 함수에 flag 를 세워 실행 여부를 구분하는 방법이다.
let callbackFlag = false;
const timer = setInterval(()=>{
       if(!callbackFlag){
         // axios.post("https://test.com").then(res=>{
         // 	clearInterval(timer);
         //   callbackFlag = true;
         // });
         // 실행할 함수 부분에서 callbackFlag 로 실행 여부를 한번 더 검증해준다.
         }
	}, 100);

위와 같이 실행 여부를 한번 더 구분해준다.

간단한 해결책이지만, 이 방법을 생각못해 일주일 간 에러와 싸우게 되었다.

위 방법은 이곳 에서 참고하여 사용했다.

profile
프론트엔드 개발자 김영준 입니다. 디테일함을 키우고 있습니다

0개의 댓글