...
디버깅(Debugging)
디버깅(Debugging)은 컴퓨터에서 발생한 오류를 찾기 위해 소스 코드를 한 줄씩 따라가면서 변수값의 변화를 검사하는 과정입니다.
중단점 (breakpoint)
기능 단위로 구현하는 경우가 많으므로 하나의 기능이 끝날 때마다 여러가지 테스트, 디버깅이 필요할 수 있습니다.
여기서 중단점(Breakpoint)은 스크립트의 동작을 잠시 멈추도록하여 디버깅이 가능하게 해줍니다.
이때 원하는 위치에 중단점을 설정하여야 하는데 중단점을 추가하는 방법은 아래와 같이 두 가지 방법을 사용합니다.
i. 작성한 코드의 필요한 부분에 debugger 키워드를 추가하기
코드에 직접 debugger;라는 코드를 추가하는 방법입니다.
개발을 하는 도중 필요하다고 판단 즉시 코드를 추가하므로 빠르고 간단한 방법입니다.
다만 어플리케이션을 재시작해야 한다는 단점이 있습니다.
코드의 중간에 debugger를 넣을 경우 스크립트가 실행되면서 debugger를 만나게 되면 해당 위치에서 코드 실행이우 중단됩니다.
이때 반드시 개발자 도구가 열려 있어야 합니다.
debugger를 만난다고 자동으로 브라우저 개발자 도구가 실행되지는 않으니 주의하세요.
ii. 브라우저의 개발자도구의 소스 코드에 설정하기
브라우저에 나타나는 소스에서 중단점을 설정하는 방법입니다.
이 방법의 장점은 재시작, 빌드 없이 바로 마우스를 사용해 원하는 곳에 설정할 수 있다는 점입니다.
크롬 디버깅 사용법
크롬 브라우저에서 f12를 눌러 개발자 도구를 엽니다.
상단의 Sources 패널을 처음 열었다면 아래와 같은 화면이 보일 겁니다.
Sources 패널은 크게 세 개의 영역으로 구성됩니다.
- 파일 탐색 영역 – 페이지를 구성하는 데 쓰인 모든 리소스(HTML, JavaScript, CSS, 이미지 파일 등)를 트리 형태로 보여줍니다. Chrome 익스텐션이 여기 나타날 때도 있습니다.
- 코드 에디터 영역 – 리소스 영역에서 선택한 파일의 소스 코드를 보여줍니다. 여기서 소스 코드를 편집할 수도 있습니다.
- 자바스크립트 디버깅 영역 – 디버깅에 관련된 기능을 제공합니다.
Watch – 표현식을 평가하고 결과를 보여줍니다.
Add Expression 버튼 +를 클릭해 원하는 표현식을 입력한 후 Enter를 누르면 중단 시점의 값을 보여줍니다.
입력한 표현식은 실행 과정 중에 계속해서 재평가됩니다.
Call Stack – 코드를 해당 중단점으로 안내한 실행 경로를 역순으로 표시합니다.
실행은 index.html 안에서 hello()를 호출하는 과정 중에 멈췄습니다.
함수 hello 내에 중단점을 설정했기 때문에, 콜 스택(Call Stack) 최상단엔 hello가 위치합니다.
index.html에서 함수 hello를 정의하지 않았기 때문에 콜 스택 하단엔 'anonymous’가 출력됩니다.
콜 스택 내의 항목을 클릭하면 디버거가 해당 코드로 휙 움직이고, 변수 역시 재평가됩니다.
Scope – 현재 정의된 모든 변수를 출력합니다.
Local은 함수의 지역변수를 보여줍니다. 지역 변수 정보는 소스 코드 영역에서도 확인(강조 표시)할 수 있습니다.
Global은 함수 바깥에 정의된 전역 변수를 보여줍니다.
Local 하위 항목으로 this에 대한 정보도 출력되는데, 이에 대해선 추후에 학습하도록 하겠습니다.
디버깅 아이콘
– ‘Resume’: 스크립트 실행을 다시 시작함 (단축키 F8)
– ‘Step’: 다음 명령어를 실행함 (단축키 F9)
– ‘Step over’: 다음 명령어를 실행하되, 함수 안으로 들어가진 않음 (단축키 F10)
'Step’과 유사하지만, 다음 문이 함수 호출일 때 'Step’과는 다르게 동작합니다(alert 같은 내장함수에는 해당하지 않고, 직접 작성한 함수일 때만 동작이 다릅니다).
'Step’은 함수 내부로 들어가 함수 본문 첫 번째 줄에서 실행을 멈춥니다.
반면 'Step over’는 보이지 않는 곳에서 중첩 함수를 실행하긴 하지만 함수 내로 진입하지 않습니다.
실행은 함수 실행이 끝난 후에 즉시 멈춥니다.
'Step over’은 함수 호출 시 내부에서 어떤 일이 일어나는지 궁금하지 않을 때 유용합니다.
– ‘Step into’ (단축키 F11)
'Step’과 유사한데, 비동기 함수 호출에서 'Step’과는 다르게 동작합니다.
'Step’은 setTimeout같은 비동기 동작은 무시합니다.
반면 'Step into’는 비동기 동작을 담당하는 코드로 진입하고, 필요하다면 비동기 동작이 완료될 때까지 대기합니다.
– ‘Step out’: 실행 중인 함수의 실행이 끝날 때 까지 실행을 계속함 (단축키 Shift+F11)
현재 실행 중인 함수의 실행을 계속 이어가다가 함수 본문 마지막 줄에서 실행을 멈춥니다.
실수로 눌러 내부 동작을 알고 싶지 않은 중첩 함수로 진입했거나 가능한 한 빨리 함수 실행을 끝내고 싶은 경우 유용합니다,
– 모든 중단점을 활성화/비활성화 (실행에는 영향이 없습니다).
– 예외 발생 시 코드를 자동 중지시켜주는 기능을 활성화/비활성화
활성화되어 있고, 개발자 도구가 열려있는 상태에서 스크립트 실행 중에 에러가 발생하면 실행이 자동으로 멈춥니다.
실행이 중단되었기 때문에 변수 등을 조사해 어디서 에러가 발생했는지 찾을 수 있게 됩니다.
개발하다가 에러와 함께 스크립트가 죽었다면 디버거를 열고 이 옵션을 활성화한 후, 페이지를 새로 고침하면 에러가 발생한 곳과 에러 발생 시점의 컨텍스트를 확인할 수 있습니다.
크롬 디버깅 예제)
1) 1부터 n까지의 숫자를 반복한다.
2) 3의 배수는 "fizz"라는 문구를 콘솔에 출력한다.
3) 5의 배수는 "buzz"라는 문구를 콘솔에 출력한다.
4) 3과 5의 공배수는 "fizzbuzz"라는 문구를 출력한다.
5) 어디에도 해당되지 않는 숫자는 그냥 숫자를 출력한다
function fizzbuzz (n) {
for (var i = 1; i < n + 1; i++) {
if (i % 3 === 0) {
if (i % 5 === 0) {
console.log('fizzbuzz');
}
console.log('fizz');
} else if (i % 5 === 0) {
console.log('buzz');
} else {
console.log(i);
}
}
}
console.log(fizzbuzz(100));
디버깅 테스트를 하기 위해서 위 코드를 일부러 잘못된 코드로 수정해보았습니다.
function fizzbuzz (n) {
for (var i = 1; i < n + 1; i++) {
if (i % 3 === 0) {
console.log('fizz');
} else if (i % 5 === 0) {
console.log('buzz');
} else if (i % 3 === 0 && i % 5 === 0) { //잘못된 논리 제어문
console.log('fizzbuzz');
} else {
console.log(i);
}
}
}
console.log(fizzbuzz(100));
위 코드가 잘못된 이유는 3과 5의 공배수를 구하는 if문의 위치입니다.
3과 5의 공배수는 이미 3의 배수 구하는 첫 번째 if문에 걸리기 때문에 fizz를 출력하고 if문을 빠져나가게 되므로 fizzbuzz를 출력할 수 없습니다.
* 만약에 위 조건식을 그대로 쓰면서 원래 의도되로 실행되게 하려면
if (i % 3 === 0 && i % 5 ===0) 조건문을 if문 맨 처음에 쓰면 됩니다.
그러면 3의 배수와 5의 배수를 둘 다 만족하는 지 가장 먼저 체크하여 공배수를 구하고, 그 다음으로 3의 배수, 5의 배수를 각각 체크하므로 원하는 결과가 출력됩니다.
코드를 실행해보면 3과 5의 공배수인 15가 출력될 자리에 "fizzbuzz"대신 "fizz"가 찍혀있는 것을 확인할 수 있습니다.
그럼 이제 어느 부분에서 오류가 났는지 확인해보기 위해 디버깅을 실행해봅시다.
먼저 debugger; 코드를 삽입합니다.
function fizzbuzz (n) {
for (var i = 1; i < n + 1; i++) {
debugger;
if (i % 3 === 0) {
console.log('fizz');
} else if (i % 5 === 0) {
console.log('buzz');
} else if (i % 3 === 0 && i % 5 === 0) {
console.log('fizzbuzz');
} else {
console.log(i);
}
}
}
console.log(fizzbuzz(100));
함수가 실행을 하다가 제가 debugger; 라고 작성한 구문에서 멈춰서게 됩니다.
그 뿐만 아니라 현재 n 파라미터에 전달된 값이 100이라는 것과 변수 i의 값이 1이라는 것도 알려줍니다.
이 상태에서 위의 파란 버튼을 누르면 debugger라는 구문이 밑에 또 있지 않는 한 그냥 끝까지 실행합니다.
만약 실행하다가 또 다른 debugger문장이 있으면 그 자리에서 다시 멈춰섭니다.
위 버튼은 "Step over next function call", 즉 다음 함수 구문으로 넘어가는 버튼입니다.
아까 위의 상태에서 저 버튼을 누르면 다음과 같이 진행됩니다.
debugger문장에서 if문으로 넘어간 것을 확인할 수 있습니다.
이제 i가 15일 때 왜 "fizzbuzz"가 출력되지 않는지 궁금하기 때문에 i가 15가 될 때까지 계속해서 저 버튼을 눌러야할 것입니다.
하지만 만약에 15가 아니고 i가 100이 될 때가 궁금하다면 얼마나 100번이나 눌러야하죠.
그러나 다행히 그것보다 더 현명한 다른 방법을 제공합니다.
조건을 주고 싶은 위치의 줄번호에 마우스를 가져다놓고 우클릭하고 Add conditional breakpoint를 클릭합니다.
그럼 줄번호에 주황색 표시가 생겨나는 것을 확인할 수 있습니다.
위의 방법은 디버깅을 하는 도중에 조건을 추가하고 싶을 때 유용한 방법이다.
원본 코드에 debugger;구문을 작성할 때
if (i === 15) { debugger; }
이런 식으로 조건을 부여하여 작성할 수도 있습니다.
이 상태에서 파란색 버튼을 누릅니다.
그러면 함수를 실행하다가 i가 15가 되고 난 후 해당 위치에서 멈춰서게 됩니다.
이제 위 버튼을 클릭하여 어떤 로직으로 함수가 실행되는지 따라가면서 볼 수 있게 됩니다.
15일 때, 내가 원하는 방향은 (i % 3 === 0 && i % 5 === 0) 조건에 걸리는 것인데,
(i % 3 === 0) 조건에 걸리는 것을 확인할 수 있습니다.
Continue to here 옵션
특정 줄에서 마우스 오른쪽 버튼을 클릭해 컨텍스트 메뉴를 열면 "Continue to here"라는 옵션을 볼 수 있습니다.
중단점을 설정하기는 귀찮은데 해당 줄에서 실행을 재개하고 싶을 때 아주 유용한 옵션입니다.
[단축키]
F8 - 중단점을 그만하고 코드 계속 실행하기
F10 - 다음 함수 코드로 이동하기
F11 - 함수의 내부 코드로 이동
F11 + Shift - 현재 함수에서 빠져나와 다음 함수로 이동하기
# 참고자료
https://im-developer.tistory.com/84
https://webisfree.com/2017-02-01/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%A4%91%EB%8B%A8%EC%A0%90%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%94%94%EB%B2%84%EA%B9%85-%EB%B0%A9%EB%B2%95
https://ko.javascript.info/debugging-chrome
이 글이 좋으셨다면 구독 & 좋아요
여러분의 구독과 좋아요는
저자에게 큰 힘이 됩니다.