본문 바로가기
개발/Javascript

[js] 자바스크립트로 반응속도 테스트 구현

by 코딩하는 갓디노 2021. 1. 3.

 

자바스크립트를 이용하여, 
반응속도 테스트를 구현하는 예제입니다.



 

예제는 인프런의 제로초, "조현영"님의 강의를 들으면서 공부한 내용입니다.

순서도

 

특이사항

준비 화면 상태 일 때 랜덤 한 시간 후에 자동으로 테스트 화면으로 전환
setTimeout으로 
Math.floor(Math.random()*1000): 0-1초 사이 랜덤 시간 이후 
click() 자동 클릭 시킴

 

html 코드

<div id="screen" class="waiting">Click to start</div>
<div id="show"></div>

 

css 코드

#screen {
  width: 400px;
  height: 300px;
  text-align: center;
  user-select: none;
  /*해당요소의 드레그, 더블클릭, 블럭지정을 막는다.*/
  font-size: 20px;
  font-weight: bold;
}

#screen.waiting {
  background: skyblue;
}

#screen.ready {
  background: pink;
}

#screen.go {
  background: greenyellow;
}

 

순수 자바스크립트(디버깅 전)

const screen = document.querySelector('#screen');

screen.addEventListener('click', function() {
  //classList.contains로 현재 class 파악 -> return true or false
  //처음 시작 waiting 화면 -> ready 화면
  if (screen.classList.contains('waiting')) {
    screen.classList.remove('waiting');
    screen.classList.add('ready');
    screen.textContent = 'wait for green';
    //ready 화면에 되는 순간 timer 동작
    setTimeout(function() {
      let start = new Date();
      screen.click();
    }, Math.floor(Math.random() * 1000) + 2000); //2-3초 사이 랜덤한 시간 
   //ready 화면 -> go 화면
  } else if (screen.classList.contains('ready')) {
    screen.classList.remove('ready');
    screen.classList.add('go');
    screen.textContent = 'Click';
   //go 화면 -> waiting 화면
  } else if (screen.classList.contains('go')) {
    let end = new Date();
    //아래 콘솔에서 에러발생: Uncaught ReferenceError: start is not defined
    console.log((end - start) / 1000);

    screen.classList.remove('go');
    screen.classList.add('waiting');
    screen.textContent = 'Click to start';
  }
});

 

new Data()

· new Data() 하는 순간 그 시작이 저장(ms 밀리초 단위)됩니다.
· 이를 1000으로 나뉘면 초로 계산됩니다. (1000ms -> 1초)

 

비동기 함수 특징

· 비동기 함수는 이벤트(클릭)를 하는 순간 콜스택 들어갔다가 함수가 끝나면 바로 나갑니다.
· 함수 안에 {명령} 내용을 실행을 완료후 함수가 사라집니다.

 

코드 에러 발생

console.log((end - start) / 1000);
//결과 Uncaught ReferenceError: start is not defined

문제점: scope 문제

· start를 감싸고 있는 함수(click 이벤트 콜백 함수) scope안에 start 변수 선언이 없음 
· 그 바깥 전역 범위에도 없음 
· start 변수선언을 setTimeout 함수 안에 했기 때문에 밖에서 함수 접근 불가하여 undefined 에러 발생 
· 비동기 함수의 특징 때문에 실행 완료 후 콜스택의 함수가 사라지면서 start, end 변수 선언한 것이 사라짐

문제 해결 방법: 

변수선언을 전역 변수로(함수의 밖) 꺼냅니다.

 

순수 자바스크립트(디버깅 후, 추가 기능)

· scope 문제 디버깅
· ready화면에서 부정 클릭 시 코
· 3번 테스트 후 평균 반응속도 점수 출력
· 초기화

const screen = document.querySelector('#screen');
let start;
let end;
let count = 0;
let score = [];
let sum = 0;
let averageScore = 0;
let timer;

screen.addEventListener('click', function() {
  if (screen.classList.contains('waiting')) {
    screen.classList.remove('waiting');
    screen.classList.add('ready');
    screen.textContent = 'wait for green';

    //ready 화면에 되는 순간 timer 동작
    timer = setTimeout(function() { //timer 변수에 대입하여 clearTimeout에 사용
      start = new Date();
      screen.click();
    }, Math.floor(Math.random() * 1000) + 2000);
  } else if (screen.classList.contains('ready')) {
    //ready 화면에서 부정 클릭시
    if (!start) { //start가 없으면 부정 클릭
      clearTimeout(timer);
      screen.classList.remove('ready');
      screen.classList.add('waiting');
      screen.textContent = 'Clicked too soon';

    } else {
      screen.classList.remove('ready');
      screen.classList.add('go');
      screen.textContent = 'Click';
    }
  } else if (screen.classList.contains('go')) {
    end = new Date();
    result = (end - start) / 1000
    console.log(result + '초');
    count += 1;
    score.push(result);

    screen.classList.remove('go');
    screen.classList.add('waiting');
    screen.textContent = 'Click to start';

    //초기화
    start = null;
    end = null;

  }
  if (count >= 3) {
    for (let i = 0; i < score.length; i++) {
      sum = sum + score[i]
    }
    averageScore = sum / score.length;
    console.log(count, score, sum, averageScore);
    document.querySelector('#show').textContent = `당신의 평균 속도는 ${averageScore.toFixed(2)} 입니다.`;

    setTimeout(function() {
      backtoBegin();
    }, 2000);
  }

  //게임 초기화
  function backtoBegin() {
    count = 0;
    document.querySelector('#show').textContent = '';
  }
});

 

전체 코드

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <title>반응속도테스트</title>
    <style>
        #screen {
            width: 400px;
            height: 300px;
            text-align: center;
            user-select: none;
            font-size: 20px;
            font-weight: bold;
        }

        #screen.waiting {
            background: skyblue;
        }

        #screen.ready {
            background: pink;
        }

        #screen.go {
            background: greenyellow;
        }
    </style>
</head>

<body>
    <div id="screen" class="waiting">Click to start</div>
    <div id="show"></div>

    <script>
        const screen = document.querySelector('#screen');
        let start;
        let end;
        let count = 0;
        let score = [];
        let sum = 0;
        let averageScore = 0;
        let timer;

        screen.addEventListener('click', function() {
            if (screen.classList.contains('waiting')) {
                screen.classList.remove('waiting');
                screen.classList.add('ready');
                screen.textContent = 'wait for green';

                timer = setTimeout(function() { 
                    start = new Date();
                    screen.click();
                }, Math.floor(Math.random() * 1000) + 2000);
            } else if (screen.classList.contains('ready')) {
                if (!start) { 
                    clearTimeout(timer);
                    screen.classList.remove('ready');
                    screen.classList.add('waiting');
                    screen.textContent = 'Clicked too soon';

                } else {
                    screen.classList.remove('ready');
                    screen.classList.add('go');
                    screen.textContent = 'Click';
                }
            } else if (screen.classList.contains('go')) {
                end = new Date();
                result = (end - start) / 1000
                console.log(result + '초');
                count += 1;
                score.push(result);

                screen.classList.remove('go');
                screen.classList.add('waiting');
                screen.textContent = 'Click to start';

                //초기화
                start = null;
                end = null;

            }
            if (count >= 3) {
                for (let i = 0; i < score.length; i++) {
                    sum = sum + score[i]
                }
                averageScore = sum / score.length;
                console.log(count, score, sum, averageScore);
                document.querySelector('#show').textContent = `당신의 평균 속도는 ${averageScore.toFixed(2)} 입니다.`;

                setTimeout(function() {
                    backtoBegin();
                }, 2000);
            }

            //게임 초기화
            function backtoBegin() {
                count = 0;
                document.querySelector('#show').textContent = '';
            }
        });
    </script>
</body>

</html>



 

화면 결과(Result 클릭)

반응형

댓글