@@ -10,24 +10,57 @@ Promise 会自动捕获内部异常,并交给 `rejected` 响应函数处理。
10
10
``` javascript
11
11
new Promise ( resolve => {
12
12
setTimeout ( () => {
13
- throw new Error ( ' bye ' );
13
+ resolve ( );
14
14
}, 2000 );
15
+ throw new Error (' bye' );
15
16
})
16
17
.then ( value => {
17
18
console .log ( value + ' world' );
18
19
})
19
20
.catch ( error => {
20
21
console .log ( ' Error: ' , error .message );
22
+ });
21
23
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)
25
52
// at ontimeout (timers.js:488:11)
26
53
// at tryOnTimeout (timers.js:323:5)
27
54
// at Timer.listOnTimeout (timers.js:283:5)
28
55
```
29
56
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 `
31
64
32
65
正如我们前面所说,` .then(fulfilled, reject) ` 其实接收两个参数,分别作为成功与失败的回调。不过在实践中,我更推荐上面的做法,即不传入第二个参数,而是把它放在后面的 ` .catch() ` 里面。这样有两个好处:
33
66
@@ -79,7 +112,9 @@ new Promise(resolve => {
79
112
80
113
## 小结
81
114
82
- 简单总结一下 Promise 的错误处理。与异步回调相比,它的作用略强,可以抛出和捕获错误,基本可以按照预期的状态执行。然而它仍然不是真正的 ` try / catch / throw ` 。` .catch ()` 也使用 ` Promise .resolve ()` 返回 ` fulfilled` 状态的 Promise 实例,所以它后面的 ` .then ()` 会继续执行,在队列很长的时候,也容易出错,请大家务必小心。
115
+ 简单总结一下 Promise 的错误处理。与异步回调相比,它的作用略强,可以抛出和捕获错误,基本可以按照预期的状态执行。然而它仍然不是真正的 ` try/catch/throw ` 。
116
+
117
+ ` .catch() ` 也使用 ` Promise.resolve() ` 返回 ` fulfilled ` 状态的 Promise 实例,所以它后面的 ` .then() ` 会继续执行,在队列很长的时候,也容易出错,请大家务必小心。
83
118
84
119
另外,所有执行器和响应函数里的错误都不会真正进入全局环境,所以我们有必要在所有队列的最后一步增加一个 ` .catch() ` ,防止遗漏错误造成意想不到的问题。
85
120
0 commit comments