인프런 커뮤니티 질문&답변

JI AE OH님의 프로필 이미지
JI AE OH

작성한 질문수

[코드캠프] 시작은 프리캠프

타이머 끝나기 전 '인증번호 전송' 누르면 타이머가 겹치는 문제

해결된 질문

작성

·

848

·

수정됨

0

안녕하세요

최종 과제에서 타이머를 다시 만드는데,
타이머 3분이 끝나기 전에 '인증번호 전송'을 다시 누르면
타이머가 겹쳐서 시간이 이상하게 표기됩니다.


수업때는 조건이 time < 0일때, clearInterval(timer) 로 해결한다고 하셨는데, 타이머 끝나기 전에는 타이머가 초기화되지않아서요...

 

아래는 제 코드와 설명입니다. (final.js 파일 안)


let isStarted = false

// 인증번호 생성 및 타이머 함수. 인증번호 버튼 onclick="startTimer()"로 되어있음.
let startTimer = () => {
    if (isStarted === false){
        isStarted = true
        // 인증번호 생성
        let token = String(Math.floor(Math.random() * 0xffff)).padEnd(6, "0")
        document.getElementById("auth__number").innerText = token

        // 인증확인 버튼 활성화 & //인증 전송 비활성화
        document.getElementById("auth__checkbtn__id").disabled = false
        //document.getElementById("auth__sendbtn__id").disabled = true

        // 타이머 시작 (5초)
        let time = 5
        let timer
        clearInterval(timer)
        timer = setInterval(() => { 
            if (time >= 0 && isStarted){ //여기 isStarted 조건 추가해 중복타이머 막음
                let min = Math.floor(time / 60)
                let sec = String(time % 60).padStart(2,"0")
                document.getElementById("auth__time").innerText = min + ":" + sec
                time = time - 1
                
            } else {
                document.getElementById("auth__checkbtn__id").disabled = true
                document.getElementById("auth__sendbtn__id").disabled = false
                //isStarted = false
                // 그렇다고 여기에 isStarted = false 더쓰면 또 겹침... 깨끗한 상태로 시작이 왜안되지?

                clearInterval(timer)
                document.getElementById("auth__time").innerText = '3:00'
                document.getElementById("auth__number").innerText = '000000'
               
            }
        }, 1000)
    } else { 
        // **타이머 작동중일때. isStarted 상태 바꾸기.. **
        // 그러나 다시 If문을 진입해 타이머 재시작하려면 다시 [인증 전송]버튼 눌러야함
        isStarted = false
        console.log('타이머 작동중임')
        // clearInterval(timer)는 위의 If문 안에있어 불러올 수 없음.
        // startTimer()를 재귀적으로 불러오면 또 다시 타이머 겹침
    }
}


<로직>
1. 타이머가 작동중이지 않을때 버튼 누름 (isStarted = false 상태)
2. 타이머 시작 (isStarted = true 상태)
3. ** 타이머가 작동중일때 [인증 전송 버튼] 다시 누름 (isStarted = false로 바꿈) **
--> 타이머가 재시작 하지 않음 (함수는 else문에서 끝났기 때문)
4. 재시작위해 [인증 전송버튼] 다시 누름 (3단계에서 isStarted가 false로 바뀌어서 이제 타이머 다시시작)

**표시 있는 else문**(3단계)에서 IsStarted = false로 바뀌고 else문이 끝났기 때문에,
다시 타이머를 시작하도록 재귀적으로 startTimer()함수를 실행하면 또 타이머가 겹칩니다.

ㅠㅠ 이렇게 저렇게 바꿔봐도 해결이 안되서 그냥 인증과 동시에 인증번호생성 버튼을 비활성화 시켰습니다...

 

어떻게 타이머 작동중에 [인증 전송]버튼 누르면 겹침문제없이 다시 타이머가 초기화되도록 할 수 있나요?

 

답변 1

1

안녕하세요 JI AE OH 님!

질문해 주신 내용을 확인해 보니, 인증번호 전송 버튼을 누른 후, 타이머가 종료되기 이전에 새로운 인증번호를 발급받았을 때의 interval 반복을 해결하고 싶으신 것 같네요!

timer 변수가 clearInterval에 넘겨 줄 interval을 담고 있지만, else 문안에서는 참조가 불가능해, 어려움을 겪고 있으시군요.

우선 timer 변수는 선언이 먼저 진행된 뒤, interval이 생성되면 해당 interval을 timer 변수에 담아주고 있습니다.

즉, 해당 변수는 interval이 생성되는 위치에서 참조만 가능하다면, 어디에서 선언되어도 문제가 없겠죠?

따라서 if 문과 else 문, 두 괄호 내에서 모두 참조가 가능하도록 startTimer 함수 바깥으로 timer 변수의 선언부를 옮겨 주신다면, 원하시던 부분의 구현이 가능할 것 같아 보이네요!

생각하셨던 것처럼 재귀 호출 또한 필요할 듯 보여지고요!

함수 안이 아닌 바깥에서 timer를 선언해 주어야 하는 이유는, 함수가 실행될 때마다 새로운 timer 변수가 선언되고 새로운 interval이 담기게 된다면 이후 다시 startTimer 함수를 실행했을 때는 이전에 생성된 timer 변수, 그 안에 담긴 interval에 접근하는 것이 불가능하기 때문이죠!

전역에 timer 변수가 선언된다면, 해당 변수는 페이지가 로드될 때, 한번 선언된 뒤에 우리가 startTimer 함수를 실행할 때마다 기존에 timer에 담겼던 interval을 삭제해 주고, 새로운 interval을 담아주기 때문에 말씀해 주신 부분의 구현이 가능하리라 생각됩니다!

JI AE OH님의 프로필 이미지
JI AE OH
질문자

감사합니다 그렇게 해보겠습니다.

JI AE OH님의 프로필 이미지
JI AE OH

작성한 질문수

질문하기