「번역」공식 가이드 시리즈: JavaScript 디버깅 가이드 (1)

✍🏼 작성일 2022년 09월 13일    💡 수정일 2022년 09월 13일
❗️ 참고: 이 글이 작성된 지 이미 일이 지났습니다. 시의성에 유의하세요
🖥  설명:공식 가이드 시리즈 1탄
📚  Craft에도 게시: https://www.craft.do/s/kyKcQKCEQjAksv

이 포괄적인 Chrome DevTools 디버깅 기능 소개를 통해 여러분의 디버깅 과정이 한층 더 나아지길 바랍니다.

먼저, 기본적인 디버깅 기술을 여기 (영문, 번역 필요)에서 학습해야 할 수도 있습니다.

코드를 중단점으로 일시 정지하기

중단점을 설정하여 코드 실행 도중에 일시 정지할 수 있습니다.

중단점을 설정하는 방법은 여기 (영문, 번역 필요)에서 확인하세요.

마우스 오버 시 클래스/함수 속성 확인하기

코드 실행이 일시 정지된 상태에서 클래스나 함수명 위에 마우스를 올리면 해당 속성을 미리 볼 수 있습니다.

1

코드 단계별 실행

코드가 일시 중지된 후에는 한 번에 한 줄씩 코드를 실행하여 호출 스택과 관련 속성 값을 파악할 수 있습니다.

현재 코드 줄 건너뛰기(Step over)

현재 조사 중인 문제와 관련이 없는 코드 줄에 중단점이 설정되어 있고, 해당 줄에 함수가 포함된 경우 Step Over를 클릭하여 함수 내부로 진입하지 않고 코드 실행을 계속할 수 있습니다.

step_over

그림 1 👆🏻, 위 이미지에서 파란색 상자 안의 Step Over의 의미 설명:

예를 들어, 다음과 같은 코드를 디버깅하고 있다고 가정해 보겠습니다:

1
2
3
4
5
6
7
8
9
function updateHeader() {
var day = new Date().getDay();
var name = getName(); // A
updateName(name); // D
}
function getName() {
var name = app.first + ' ' + app.last; // B
return name; // C
}

현재 브레이크포인트가 A 위치에서 멈춰 있습니다. Step over를 클릭하면 Devtools는 ‘Step over’ 위치에 있는 모든 코드를 실행합니다. 위 예시에서 'Step over’는 A 위치의 getName 함수 내 BC 위치를 건너뛰므로, Devtools는 코드를 D 위치에서 멈추게 됩니다.

현재 코드 라인 진입(Step into)

브레이크포인트가 조사하려는 문제와 관련된 위치에 멈추었고, 해당 위치에 함수 호출이 포함된 경우 Step into를 클릭하면 해당 함수를 더 자세히 검사할 수 있습니다.

step_into

그림 2 👆🏻, 위 그림의 파란색 상자 안에 있는 Step into의 의미 설명:

예를 들어, 다음과 같은 코드를 디버깅하고 있다고 가정해 보겠습니다:

1
2
3
4
5
6
7
8
9
function updateHeader() {
var day = new Date().getDay();
var name = getName(); // A
updateName(name);
}
function getName() {
var name = app.first + ' ' + app.last; // B
return name;
}

현재 중단점이 A 위치에 멈춰 있는 상태에서 Step into를 클릭하면 Devtools가 해당 코드를 실행한 후 B 위치에서 멈춥니다.

현재 코드 라인에서 벗어나기(Step out)

조사 중인 문제와 관련이 없는 함수 내부에서 중단점이 멈춰 있을 때, Step out을 클릭하면 해당 함수의 남은 코드를 실행합니다.

step_out

그림 3 👆🏻, 위 그림의 파란색 상자 안에 있는 Step out의 의미 설명:

예를 들어, 다음과 같은 코드를 디버깅하고 있다고 가정해 보겠습니다:

1
2
3
4
5
6
7
8
9
function updateHeader() {
var day = new Date().getDay();
var name = getName();
updateName(name); // C
}
function getName() {
var name = app.first + ' ' + app.last; // A
return name; // B
}

당신의 중단점이 A 위치에 멈춰 있을 때, Step out을 클릭하면 DevTools는 getName() 함수의 남은 코드, 즉 B 위치의 코드를 실행한 후, 중단점을 C 위치에서 멈추게 됩니다.

지정된 행까지 코드 계속 실행하기

매우 긴 함수를 디버깅할 때, 함수 내부에는 현재 조사 중인 문제와 관련 없는 많은 코드가 포함될 수 있습니다.

이러한 관련 없는 코드를 한 단계씩 실행할 수도 있지만, 이 과정은 지루할 수 있습니다. 또는 중단하고 싶은 코드 행에 중단점을 설정한 후 Resume Script Execution(스크립트 실행 재개)을 누를 수도 있습니다. 그러나 더 빠른 방법이 있습니다.

중단하고 싶은 코드 행을 우클릭한 후 Continue to here(여기까지 계속 실행)을 선택할 수 있습니다. DevTools는 중단점을 재개하여 해당 위치까지 코드를 실행한 후, 그 행에서 멈출 것입니다.

continue_to_here

그림 4 👆🏻에서 Continue to here를 선택하세요.

스크립트 실행 재개

Resume Script Execution을 클릭하면 중단점에서 일시 정지된 위치부터 코드 실행을 계속할 수 있습니다. Devtools는 다음 중단점(있는 경우)을 만날 때까지 코드를 계속 실행합니다.

resume_script_execution

그림 5 👆🏻, Resume Script Execution, 파란색 상자 부분.

강제 실행

Resume Script Execution을 길게 누른 후 Force Script Execution을 선택하면 남은 모든 중단점을 무시하고 전체 코드를 직접 실행할 수 있습니다.

force_script_execution

그림 6 👆🏻에서 Force Script Execution을 선택하세요.

현재 스레드의 컨텍스트 변경

디버깅이 Web Worker나 Service Worker와 관련된 경우, Threads 표시줄에 나타나는 컨텍스트 목록 항목을 클릭하여 컨텍스트를 전환할 수 있습니다. 파란색 화살표는 현재 선택된 컨텍스트를 나타냅니다.

change_threads_context

그림 7 👆🏻, Threads (스레드) 탭에서 파란색 상자로 표시된 부분입니다.

예를 들어, 다음과 같은 시나리오를 가정해 보겠습니다. 중단점이 메인 스크립트와 서비스 워커 스크립트에 동시에 존재하는 경우입니다. 서비스 워커의 지역 변수와 전역 변수를 확인하고 싶지만, Source 탭에는 현재 메인 스크립트의 컨텍스트가 표시되고 있습니다. 이때 Threads 탭에서 서비스 워커 항목을 클릭하면 컨텍스트를 전환하여 원하는 변수를 확인할 수 있습니다.

지역, 클로저, 전역 스코프의 변수/속성 확인 및 편집

특정 라인에서 실행이 일시 중지된 경우, Scope 탭을 사용하여 지역, 클로저, 전역 변수를 확인하고 편집할 수 있습니다.

  • 속성 값을 더블 클릭하여 수정합니다.

  • 열거 불가능한 속성은 회색으로 강조 표시됩니다.

查看和修改变量

그림 8 👆🏻, Scope (스코프) 섹션에서 파란색 상자로 표시된 위치.

현재 호출 스택 확인하기

코드 실행이 특정 라인에서 일시 중지된 상태일 때, Call Stack 섹션을 사용하여 현재 중단점까지 이어지는 함수 호출 스택을 확인할 수 있습니다.

코드에 비동기 코드가 포함된 경우, Async 체크박스를 선택하여 비동기 함수 호출 스택을 활성화할 수 있습니다.

항목 중 하나를 클릭하면 해당 항목이 나타내는 함수의 호출 위치로 이동합니다. 파란색 화살표 아이콘은 현재 강조 표시된 함수를 나타냅니다.

查看函数调用栈

그림 9 👆🏻, Call Stack(호출 스택) 창에서 파란색 상자 위치.

참고: 코드가 특정 줄에서 일시 정지되지 않은 경우 Call Stack 창은 비어 있습니다.

스택 내 함수 재실행

때로는 특정 함수의 실행 상황을 관찰하고 싶지만 전체 디버깅 프로세스를 다시 실행하고 싶지 않을 때, 해당 함수 내부에서 중단점이 일시 정지된 상태에서 해당 함수만 다시 실행할 수 있습니다. 즉, 호출 스택에 해당 함수의 호출 컨텍스트를 다시 넣을 수 있습니다.

참고: WebAssembly, async, generator 함수를 제외하고 Call Stack(호출 스택) 내의 어떤 함수든 처음부터 다시 실행할 수 있습니다.

함수를 재실행하려면:

  1. 중단점을 사용하여 함수를 일시 정지시키면, Call Stack 창에 함수 호출 순서가 기록됩니다.

  2. Call Stack 창에서 함수를 우클릭한 후 나타나는 메뉴에서 Restart frame(함수 재실행)을 선택합니다.

重新执行断点所在的函数

재시작 프레임(Restart frame)이 어떻게 실행되는지 이해하기 위해, 다음과 같은 코드가 있다고 가정해 봅시다:

1
2
3
4
5
6
7
8
9
10
11
12
function foo(value) {
console.log(value);
bar(value);
}

function bar(value) {
value++;
console.log(value);
debugger;
}

foo(0);

foo 함수는 0을 매개변수로 받아 console에 log를 출력한 후 bar() 함수를 호출합니다. 이에 대응하여 bar 함수는 이 값을 1 증가시킵니다.

다음과 같은 방법으로 이 두 함수를 처음부터 실행해 보세요:

  • 위 코드를 snippet에 복사한 후 실행하세요. 중단점은 debugger가 위치한 코드 라인에서 멈출 것입니다.

    ⚠️ 주의: 코드 실행이 일시 중지된 상태에서는 현재 호출 스택에 있는 함수를 콘솔에서 실행하지 마세요. 이는 예기치 않은 오류를 발생시킬 수 있습니다.

  • 현재 debugger가 위치한 함수 선언 오른쪽에 현재 값 value = 1이 표시되는 것을 확인할 수 있을 것입니다.

注意函数声明处右侧的值

  • bar() 함수를 처음부터 다시 실행합니다.

重头执行bar

  • F9 키를 누르면, 값이 증가하는 해당 코드 줄을 지나갈 수 있으며, 다시 디버거에서 중단됩니다.

    값이 2로 변경된 것을 확인하세요: value = 2.

重头执行debugger

  • 이 외에도 Scope 창에서 value 값을 더블 클릭하여 원하는 값으로 편집할 수 있습니다.

双击编辑值

  • bar() 함수를 여러 번 다시 실행해 보면 값이 계속 증가하는 것을 확인할 수 있습니다.

多次重复执行后值会一直增加

💡 놀랍죠! 왜 value0으로 재설정되지 않을까요?

함수를 처음부터 다시 실행할 때 매개변수는 재설정되지 않습니다. 달리 말하면, 처음부터 다시 실행한다고 해서 함수가 호출될 당시의 초기 상태로 복원되는 것은 아닙니다. 따라서 이는 단순히 호출 스택에서 현재 호출 포인터를 함수의 시작 위치로 이동시키는 것뿐입니다.

따라서 현재 매개변수 값인 value는 동일한 함수가 반복 실행되는 동안 메모리에 계속 존재하게 됩니다.

  • 이제 Call Stack에서 foo() 함수를 처음부터 다시 실행해 보세요.

重头执行foo函数

주의해서 보세요, value가 다시 0으로 변했습니다.

value重新变为0

💡 다시 한번 놀랍네요! 왜 이번에 value0으로 재설정되었을까요?

간단합니다(의역 적용). JavaScript에서 매개변수는 값에 의해 전달됩니다. value가 원시 값이기 때문에 함수 내에서 값을 수정해도 함수 외부의 값에는 영향을 주지 않습니다.

호출 스택 실행 경로 복사하기

Call Stack 창의 아무 곳이나 마우스 오른쪽 버튼으로 클릭한 후 Copy Stack Trace(스택 추적 복사)를 선택하면 현재 호출 스택을 클립보드에 복사할 수 있습니다.

复制调用栈

그림 10 👆🏻에서 스택 트레이스 복사를 선택합니다.

복사된 내용은 대략 다음과 같을 것입니다:

1
2
3
getNumber1 (get-started.js:35)
inputsAreEmpty (get-started.js:22)
onClick (get-started.js:15)

특정 스크립트 또는 특정 조건을 충족하는 스크립트 무시하기

디버깅 중에 특정 스크립트를 무시하여 건너뛸 수 있습니다. 일반적으로 해당 스크립트의 함수가 복잡하고 이해하기 어려우며 현재 디버깅 중인 내용과 관련이 없는 경우에 이를 무시하도록 선택합니다.

예를 들어, 다음과 같은 코드를 디버깅 중이라고 가정해 보겠습니다:

1
2
3
4
5
function animate() {
prepare();
lib.doFancyStuff(); // A
render();
}

A는 신뢰할 수 있는 서드파티 라이브러리입니다. 조사 중인 문제가 이 서드파티 라이브러리와 관련이 없다고 확신한다면, 이를 무시하는 것이 현명한 결정일 수 있습니다.

Source 편집기에서 특정 스크립트 무시하기

  1. 파일 열기

  2. 아무 위치에서 마우스 오른쪽 버튼 클릭

  3. Add script to ignore list(스크립트를 무시 목록에 추가) 선택

忽略脚本

그림 11 👆🏻, 에디터 바에서 스크립트 하나를 무시하는 방법.

Call Stack(호출 스택) 바에서 특정 스크립트 무시하기

호출 스택에서 특정 스크립트를 무시하려면 다음 단계를 따르세요:

  1. 호출 스택 내의 함수를 마우스 오른쪽 버튼으로 클릭합니다.

  2. Add script to ignore list를 선택합니다.

从调用栈中忽略脚本

그림 12 👆🏻, Call Stack(호출 스택)에서 특정 스크립트를 무시하기.

Settings(설정)에서 특정 스크립트 무시하기

역자 주: 여기서의 설정은 Devtools의 설정이며, 브라우저의 설정이 아닙니다.

설정에서 특정 스크립트나 특정 조건을 만족하는 스크립트를 무시하려면 다음 단계를 따르세요:

  1. 설정 열기:

  2. Ignore List 탭을 클릭합니다.

  3. Add pattern을 클릭합니다.

  4. 무시할 스크립트 이름이나 정규식을 입력하여 스크립트 이름과 매칭시킵니다.

  5. Add를 클릭합니다.

devoools设置界面

devtools忽略脚本

그림 13 👆🏻, Setting에서 스크립트를 무시하세요.

모든 페이지에서 디버그 코드 스니펫(Snippets) 실행하기

콘솔에서 일부 디버그 코드를 반복적으로 실행하고 있다면 스니펫을 고려해볼 수 있습니다. 스니펫은 Devtools에 저장하고 실행할 수 있는 스크립트입니다.

자세한 내용은 https://developer.chrome.com/docs/devtools/javascript/snippets/ (번역되지 않음)을 참조하세요.

역자 주: 스니펫은 실행 시 현재 컨텍스트를 가지고 있습니다. 예를 들어 디버깅 중에 일시 중지한 후 스니펫 코드를 실행하면, 해당 스니펫 코드는 현재 컨텍스트의 변수에 접근할 수 있습니다.

사용자 정의 JavaScript 표현식 값 Watch(감시)하기

Watch 패널을 사용하여 사용자 정의 표현식의 값을 모니터링할 수 있습니다. 유효한 모든 JavaScript 표현식을 감시할 수 있습니다.

监听JavaScript表达式

그림 14 👆🏻에서 파란색으로 표시된 부분이 Watch(감시) 패널입니다.

  • Add Expression(표현식 추가)를 클릭하여 새로운 감시 표현식을 생성합니다.

  • Refresh(새로 고침)을 클릭하면 기존의 모든 표현식이 갱신됩니다. 코드가 실행될 때 값은 자동으로 업데이트됩니다.

  • 표현식 위에 마우스를 올린 후 Delete Expression(표현식 삭제)를 클릭하면 해당 표현식을 삭제할 수 있습니다.

압축된 코드를 가독성 있게 포맷팅하기

Format {}을 클릭하면 압축된 코드를 사람이 읽기 쉬운 형식으로 변환할 수 있습니다.

格式化压缩后的文件

스크립트 편집하기

버그를 수정할 때는 자주 JavaScript 코드의 수정 효과를 테스트해야 합니다. 외부 편집기에서 JavaScript 코드를 편집한 후 현재 페이지로 돌아와 새로 고침하여 결과를 확인할 필요가 없습니다. Devtools에서 직접 JavaScript 코드를 편집할 수 있습니다.

스크립트를 편집하려면 다음 단계를 따르세요:

  1. Source 탭에서 편집하려는 파일을 엽니다(Editor 탭에 나타납니다).

  2. Editor 탭에서 수정을 진행합니다.

  3. Command + S(Mac) 또는 Ctrl + S(Windows, Linux)를 눌러 변경 사항을 저장합니다. Devtools는 전체 js 파일을 패치 형태로 Chrome의 JavaScript 엔진에 적용할 것입니다.

直接编辑js文件

위 그림에서 파란색 상자로 표시된 부분이 편집기 바입니다.

일시 중지된 함수 실시간 편집하기

주의: 이 기능은 Chrome 105 버전 이상에서만 사용 가능합니다.

코드가 일시 중지된 상태에서 현재 함수를 편집하고 실시간으로 수정 사항을 적용할 수 있지만, 다음과 같은 제한이 있습니다:

  • Call Stack의 최상위 함수(즉, 현재 중단점이 위치한 함수)만 편집할 수 있습니다.

  • 호출 스택에 동일한 함수에 대한 재귀 호출이 없어야 합니다(그렇지 않으면 현재 호출 스택이 아닌 함수를 수정하는 것과 같습니다).

💡 일시 중지된 함수 실시간 편집의 진실…
수정 사항을 적용할 때 디버거 도구는 자동으로 함수를 다시 실행합니다(앞서 설명한 "스택의 함수 다시 실행"과 동일). 따라서 다시 실행할 수 있는 함수에 대한 제한 사항은 실시간 편집이 적용되는 일시 중지된 함수와 동일합니다. WebAssembly, 비동기(async), 제너레이터(이터레이터) 함수는 처음부터 다시 실행할 수 없습니다.

함수를 실시간으로 편집하려면 다음 단계를 따르세요:

  1. 중단점을 사용해 실행을 일시 중지합니다.

  2. 중단점이 위치한 일시 중지된 함수를 편집합니다.

  3. Command/Control+S를 눌러 변경 사항을 적용하면 디버거가 자동으로 해당 함수를 다시 실행합니다.

  4. 실행을 계속합니다.

이 예시에서, addend1addend2 변수는 처음에 잘못된 string 타입을 가지고 있습니다. 따라서 숫자가 더해지는 대신 문자열이 잘못 연결되었습니다. 이 문제를 해결하기 위해 실시간 편집 중에 parseInt() 함수를 추가했습니다.

스크립트 내에서 텍스트 검색 및 교체

스크립트에서 특정 텍스트를 검색하려면 다음 단계를 따르세요:

  1. 코드 소스(Sources) - 편집기(Editor) 탭에서 파일을 엽니다.

  2. Command+F(Mac) 또는 Ctrl+F(Windows, Linux)를 눌러 내장 검색창을 엽니다.

  3. 검색창에 찾고자 하는 문자열을 입력하세요:

    추가적으로 다음을 할 수 있습니다:

    • Aa를 클릭하여 대소문자를 구분하는 검색을 활성화할 수 있습니다.

    • .*를 클릭하여 정규 표현식 검색을 사용할 수 있습니다.

  4. Enter 키를 눌러 검색을 실행합니다. 위/아래 화살표를 눌러 다음/이전 검색 결과로 이동할 수 있습니다.

搜索字符

검색 결과를 바꾸고 싶다면 다음 단계를 따르세요:

  1. 검색창을 열고 A→B (직접 그린 것이 아니라 아래 그림을 참고하세요) 즉 ‘바꾸기’ 버튼을 클릭하여 텍스트를 교체합니다.

  2. 교체할 텍스트를 입력한 후 Replce 또는 Replace all을 클릭하면 됩니다.

按下替换按钮

JavaScript 비활성화

자세한 내용은 Disable JavaScript With Chrome DevTools를 참조하세요(번역되지 않음).

- EOF -
이 글의 최초 게시: 「번역」공식 가이드 시리즈: JavaScript 디버깅 가이드 (1) - Xheldon Blog