Skip to content

Commit d86e213

Browse files
committed
Update chapter 47, chapter 48, chapter 49
1 parent 401b7f5 commit d86e213

4 files changed

Lines changed: 972 additions & 0 deletions

File tree

book/_toc.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,27 @@ parts:
7474
- file: 이용우/chapter_24
7575
- file: 이용우/chapter_25
7676
- file: 이용우/chapter_26
77+
- file: 이용우/chapter_27
78+
- file: 이용우/chapter_28
79+
- file: 이용우/chapter_29
80+
- file: 이용우/chapter_30
81+
- file: 이용우/chapter_31
82+
- file: 이용우/chapter_32
83+
- file: 이용우/chapter_33
84+
- file: 이용우/chapter_34
85+
- file: 이용우/chapter_35
86+
- file: 이용우/chapter_36
87+
- file: 이용우/chapter_37
88+
- file: 이용우/chapter_38
89+
- file: 이용우/chapter_39
90+
- file: 이용우/chapter_40
91+
- file: 이용우/chapter_41
92+
- file: 이용우/chapter_42
93+
- file: 이용우/chapter_43
94+
- file: 이용우/chapter_44
95+
- file: 이용우/chapter_45
96+
- file: 이용우/chapter_46
97+
- file: 이용우/chapter_47
98+
- file: 이용우/chapter_48
99+
- file: 이용우/chapter_49
77100

book/이용우/chapter_47.md

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
### Chapter 47 - 에러 처리
2+
3+
`try ... catch` 문을 사용해 발생한 에러에 적절하게 대응하면 프로그램이 강제 종료되지 않고
4+
계속해서 코드를 실행시킬 수 있다.
5+
6+
``` js
7+
console.log('[Start');
8+
9+
try {
10+
foo();
11+
} catch (err) {
12+
console.log('Error!');
13+
}
14+
```
15+
16+
직접적으로 에러를 발생시키지 않는 예외(exception)적인 상황이 발생할 수도 있다.
17+
예외적인 상황에 적절하게 대응하지 않으면 에러로 이어질 가능성이 크다.
18+
19+
``` js
20+
// DOM에 button 요소가 존재하지 않으면 querySelector 메소드는 에러를 발생시키지 않고 null을 반환한다.
21+
const $button = document.querySelector('button');
22+
$button.classList.add('disabled'); // TypeError: Cannot read property 'classList' of null
23+
```
24+
25+
위 예제의 `querySelector` 메소드는 인수로 전달한 문자열이 CSS 선택자 문법에 맞지 않는 경우 에러를 발생시킨다.
26+
27+
<br>
28+
29+
``` js
30+
const $elem = document.querySelector('#1');
31+
// DOMException: Failed to execute 'querySelector' on 'Document': '#1' is not a valid selector.
32+
```
33+
34+
<br>
35+
36+
하지만 `querySelector` 메소드는 인수로 전달한 CSS 선택자 문자열로 DOM에서 요소 노드를 찾을 수 없는 경우 에러를 발생시키지 않고 `null`을 반환한다.
37+
이때 `if` 문으로 `querySelector` 메소드의 반환값을 확인하거나 단축 평가 또는 옵셔널 체이닝 연산자(`?.`)를 사용하지 않으면
38+
다음 처리에서 에러로 이어질 가능성이 높아진다.
39+
40+
``` js
41+
// DOM에 button 요소가 존재하지 않는 경우 querySelector 메소드는 에러를 발생시키지 않고 null을 반환한다.
42+
const $button = document.querySelector('button'); // null
43+
$button?.classList.add('disabled');
44+
```
45+
46+
<br>
47+
48+
이와 같이 에러나 예외적인 상황에 대응하지 않으면 프로그램은 강제 종료될 것이다.
49+
에러나 예외적인 상황은 너무 다양하기 때문에 아무런 조치 없이 프로그램이 강제 종료된다면 원인 파악이 어려워 대응이 힘들다.
50+
51+
<br><br>
52+
53+
### try .. catch ... finally
54+
기본적으로 예외 처리를 구현하는 방법은 크게 두 가지가 있다.
55+
`querySelector``Array#find` 메소드처럼 예외적인 상황이 발생하면 반환하는 값(`null` 또는 `-1`)을 `if`문이나
56+
단축 평가 또는 옵셔널 체이닝 연산자를 통해 확인해서 처리하는 방법과
57+
에러 처리 코드를 미리 등록해 두고 에러가 발생하면 에러 처리 코드로 점프하도록 하는 방법이 있다.
58+
59+
<br>
60+
61+
`try ... catch ... finally` 문은 두 번째 방법이다.
62+
일반적으로 이 방법을 에러 처리(error handling)라고 한다.
63+
`try ... catch ... finally` 문은 다음과 같이 3개의 코드 블록으로 구성된다.
64+
`finally` 문은 불필요하다면 생략 가능하다.
65+
66+
67+
`catch` 문도 생략 가능하지만 `catch` 문이 없는 `try` 문은 의미가 없으므로 생략하지 않는다.
68+
69+
``` js
70+
try {
71+
// 실행할 코드 (에러가 발생할 가능성이 있는 코드)
72+
} catch (err) {
73+
// try 코드 블록에서 에러가 발생하면 이 코드 블록의 코드가 실행된다.
74+
// err에는 try 코드 블록에서 발생한 Error 객체가 전달된다.
75+
} finally {
76+
// 에러 발생과 상관없이 반드시 한 번 실행된다.
77+
}
78+
```
79+
80+
<br><br>
81+
82+
### Error 객체
83+
`Error` 생성자 함수는 에러 객체를 생성한다.
84+
`Error` 생성자 함수에는 에러를 상세히 설명하는 에러 메시지를 인수로 전달할 수 있다.
85+
86+
``` js
87+
const error = new Error('invalid');
88+
```
89+
90+
`Error` 생성자 함수가 생성한 에러 객체는 `message` 프로퍼티와 `stack` 프로퍼티를 갖는다.
91+
`message` 프로퍼티의 값은 `Error` 생성자 함수에 인수로 전달한 에러 메시지이고
92+
`stack` 프로퍼티의 값은 에러를 발생시킨 콜 스택의 호출 정보를 나타내는 문자열이며 디버깅 목적으로 사용한다.
93+
94+
자바스크립트는 Error 생성자 함수를 포함해 7가지의 에러 객체를 생성할 수 있는 Error 생성자 함수를 제공한다.
95+
96+
| 생성자 함수 | 인스턴스 |
97+
| :---: | :---: |
98+
| Error | 일반적 에러 객체 |
99+
| SyntaxError | 자바스크립트 문법에 맞지 않는 문을 해석할 때 발생하는 에러 객체 |
100+
| ReferenceError | 참조할 수 없는 식별자를 참조했을 때 발생하는 에러 객체 |
101+
| TypeError | 피연산자 또는 인수의 데이터 타입이 유효하지 않을 때 발생하는 에러 객체 |
102+
| RangeError | 숫자값의 허용 범위를 벗어났을 때 발생하는 에러 객체 |
103+
| URIError | `encodeURI` 또는 `decodeURI` 함수에 부적절한 인수를 전달했을 때 발생하는 에러 객체 |
104+
| EvalError | `eval` 함수에서 발생하는 에러 객체 |
105+
106+
<br><br>
107+
108+
### throw 문
109+
`Error` 생성자 함수로 에러 객체를 생성한다고 에러가 발생하는 것은 아니다.
110+
> 즉, 에러 객체 생성과 에러 발생은 그 의미가 다르다.
111+
112+
<br>
113+
114+
``` js
115+
try {
116+
// 에러 객체를 생성한다고 에러가 발생하는 것은 아니다.
117+
new Error('something wrong');
118+
} catch (error) {
119+
console.log(error);
120+
}
121+
```
122+
123+
에러를 발생시키려면 try 코드 블록에서 `throw` 문으로 에러 객체를 던져야 한다.
124+
125+
``` js
126+
throw 표현식;
127+
```
128+
129+
`throw` 문의 표현식은 어떤 값이라도 상관없지만 일반적으로 에러 객체를 지정한다.
130+
에러를 던지면 `catch` 문의 에러 변수가 생성되고 던져진 에러 객체가 할당된다.
131+
그리고 `catch` 코드 블록이 실행되기 시작한다.
132+
133+
``` js
134+
try {
135+
// 에러 객체를 던지면 catch 코드 블록이 실행되기 시작한다.
136+
throw new Error('something wrong');
137+
} catch (error) {
138+
console.log(error);
139+
}
140+
```
141+
142+
<br>
143+
144+
예를 들어, 외부에서 전달받은 콜백 함수를 n번만큼 반복 호출하는 `repeat` gkatnfmf rngusgoqhwk.
145+
146+
`repeat` 함수는 두 번째 인수로 반드시 콜백 함수를 전달받아야 한다.
147+
만약 두 번째 인수가 아니면 `TypeError` 에러를 발생시켜보자.
148+
149+
``` js
150+
// 외부에서 전달받은 콜백 함수를 n번만큼 반복 호출한다.
151+
const repeat = (n, f) -> {
152+
// 매개변수 f에 전달된 인수가 함수가 아니면 TypeError를 발생시킨다.
153+
if (typeof f !== 'function') throw new TypeError('f must be a function');
154+
155+
for (let i = 0; i < n; i++) {
156+
f(i); // i를 전달하면서 f를 호출
157+
}
158+
};
159+
160+
try {
161+
repeat(2, 1); // 2번째 인수가 함수가 아니므로 TypeError가 발생(throw)한다.
162+
} catch (error) {
163+
console.log(error);
164+
}
165+
166+
// TypeError: f must be a function
167+
```
168+
169+
<br><br>
170+
171+
### 에러의 전파
172+
에러는 호출자(`caller`) 방향으로 전파된다.
173+
즉, 콜 스택의 아래 방향(실행 중인 실행 컨텍스트가 Push되기 직전에 Push된 실행 컨텍스트 방향)으로 전파된다.
174+
175+
``` js
176+
const foo = () => {
177+
throw Error('foo에서 발생한 에러'); // (4)
178+
};
179+
180+
const bar = () => {
181+
foo(); // (3)
182+
};
183+
184+
const baz = () => {
185+
bar(); // (2)
186+
};
187+
188+
try {
189+
baz(); // (1)
190+
} catch (err) {
191+
console.error(err);
192+
}
193+
```
194+
195+
(1)에서 `baz` 함수를 호출하면 (2)에서 `bar` 함수가 호출되고 (3)에서 `foo`함수는 (4)에서 에러를 `throw` 한다.
196+
이때 `foo` 함수가 `throw`한 에러는 다음과 같이 호출자에게 전파되어 전역에서 캐치된다.
197+
198+
<img src="https://github.com/user-attachments/assets/9052a730-cd6c-4394-89f9-61fb4265a773" >
199+
200+
이처럼 `throw`된 에러를 캐치하지 않으면 호출자 방향으로 전파된다.
201+
이때 throw된 에러를 캐지하여 적절히 대응하면 프로그램을 강제 종료시키지 않고 코드의 실행 흐름을 복구할 수 있다.
202+
203+
`throw`된 에러를 어디에서도 캐치하지 않으면 프로그램은 강제 종료된다.
204+
205+
<br><br>
206+
207+
비동기 함수나 프로미스 후속 처리 메소드의 콜백 함수는 호출자가 없다.
208+
> 테스크 큐나 마이크로테스크 큐에 일시 저장되었다가 콜 스택이 비면 이벤트 루프에 의해 콜 스택으로 Push되어 시랳ㅇ된다.
209+
210+
이때 콜 스택에 푸시된 콜백 함수의 실행 컨텍스트는 콜 스택의 가장 하부에 존재하게 된다.
211+
따라서 에러를 전달할 호출자가 존재하지 않는다.
212+
213+
<br><br>
214+
215+
끝.

0 commit comments

Comments
 (0)