Skip to content

Commit ff1ee4d

Browse files
committed
修正对 catch 捕获错误的讲述错误
1 parent d306d25 commit ff1ee4d

File tree

3 files changed

+74
-6
lines changed

3 files changed

+74
-6
lines changed

02-3-promise-error.md

+41-6
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,57 @@ Promise 会自动捕获内部异常,并交给 `rejected` 响应函数处理。
1010
```javascript
1111
new Promise( resolve => {
1212
setTimeout( () => {
13-
throw new Error('bye');
13+
resolve();
1414
}, 2000);
15+
throw new Error('bye');
1516
})
1617
.then( value => {
1718
console.log( value + ' world');
1819
})
1920
.catch( error => {
2021
console.log( 'Error: ', error.message);
22+
});
2123

22-
// 输出:
23-
// (2秒后)Error: bye
24-
// at Timeout.setTimeout [as _onTimeout] (/path/to/error.js:7:11)
24+
// 立刻输出:
25+
// Error: bye
26+
```
27+
28+
可以看到,原定2s之后 `resolve()` 并没有出现,因为在 Promise 的执行器里抛出了错误,所以立刻跳过了 `.then()`,进入 `.catch()` 处理异常。
29+
30+
这里需要注意,如果把抛出错误的语句放到回调函数里,则是另外一副光景:
31+
32+
```javascript
33+
new Promise( resolve => {
34+
setTimeout( () => {
35+
throw new Error('bye');
36+
}, 2000);
37+
})
38+
.then( value => {
39+
console.log( value + ' world');
40+
})
41+
.catch( error => {
42+
console.log( 'It\'s an Error: ', error.message);
43+
});
44+
45+
// (2s之后)输出:
46+
// ./code/2-3-catch-error.js:3
47+
// throw new Error('bye');
48+
// ^
49+
50+
// Error: bye
51+
// at Timeout.setTimeout [as _onTimeout] (/Users/meathill/Documents/Book/javascript-async-tutorial/code/2-3-catch-error.js:3:11)
2552
// at ontimeout (timers.js:488:11)
2653
// at tryOnTimeout (timers.js:323:5)
2754
// at Timer.listOnTimeout (timers.js:283:5)
2855
```
2956

30-
可以看到,2秒之后,因为在 Promise 的执行器里抛出了错误,所以跳过了 `.then()`,进入 `.catch()` 处理异常。
57+
正如[异步的问题](./01-2-issue.md)分析的那样,异步回调中,异步函数的栈,和回调函数的栈,**不是**一个栈。所以 Promise 的执行器只能捕获到异步函数抛出的错误,无法捕获回调函数抛出的错误。
58+
59+
回到上面这段代码,当回调函数抛出错误时,我们没有捕获处理,运行时就出面捕获了,于是报错、回调栈被终结。此时,Promise 对象的状态并未被改变,所以下面的 `.then()` 响应函数和 `.catch()` 响应函数都没有触发,我们看到的,只是默认的错误输出。(2017-07-19 更新)
60+
61+
这也印证了 Promise 的问题:它没有引入新的语法元素,所以无法摆脱栈断裂带来的问题。在错误处理方面,它只是“能用”,并不好用,无法达到之前的开发体验。
62+
63+
### `reject`
3164

3265
正如我们前面所说,`.then(fulfilled, reject)` 其实接收两个参数,分别作为成功与失败的回调。不过在实践中,我更推荐上面的做法,即不传入第二个参数,而是把它放在后面的 `.catch()` 里面。这样有两个好处:
3366

@@ -79,7 +112,9 @@ new Promise(resolve => {
79112

80113
## 小结
81114

82-
简单总结一下 Promise 的错误处理。与异步回调相比,它的作用略强,可以抛出和捕获错误,基本可以按照预期的状态执行。然而它仍然不是真正的 `try/catch/throw``.catch()` 也使用 `Promise.resolve()` 返回 `fulfilled` 状态的 Promise 实例,所以它后面的 `.then()` 会继续执行,在队列很长的时候,也容易出错,请大家务必小心。
115+
简单总结一下 Promise 的错误处理。与异步回调相比,它的作用略强,可以抛出和捕获错误,基本可以按照预期的状态执行。然而它仍然不是真正的 `try/catch/throw`
116+
117+
`.catch()` 也使用 `Promise.resolve()` 返回 `fulfilled` 状态的 Promise 实例,所以它后面的 `.then()` 会继续执行,在队列很长的时候,也容易出错,请大家务必小心。
83118

84119
另外,所有执行器和响应函数里的错误都不会真正进入全局环境,所以我们有必要在所有队列的最后一步增加一个 `.catch()`,防止遗漏错误造成意想不到的问题。
85120

code/2-3-1-catch.js

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
new Promise( resolve => {
2+
setTimeout( () => {
3+
resolve();
4+
}, 2000);
5+
throw new Error('bye');
6+
})
7+
.then( value => {
8+
console.log( value + ' world');
9+
})
10+
.catch( error => {
11+
console.log( 'Error: ', error.message);
12+
});

code/2-3-2-catch.js

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
new Promise( resolve => {
2+
setTimeout( () => {
3+
throw new Error('bye');
4+
}, 2000);
5+
})
6+
.then( value => {
7+
console.log( value + ' world');
8+
})
9+
.catch( error => {
10+
console.log( 'It\'s an Error: ', error.message);
11+
});
12+
13+
// ./code/2-3-catch-error.js:3
14+
// throw new Error('bye');
15+
// ^
16+
17+
// Error: bye
18+
// at Timeout.setTimeout [as _onTimeout] (/Users/meathill/Documents/Book/javascript-async-tutorial/code/2-3-catch-error.js:3:11)
19+
// at ontimeout (timers.js:488:11)
20+
// at tryOnTimeout (timers.js:323:5)
21+
// at Timer.listOnTimeout (timers.js:283:5)

0 commit comments

Comments
 (0)