@@ -10,24 +10,57 @@ Promise 会自动捕获内部异常,并交给 `rejected` 响应函数处理。
1010``` javascript
1111new 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
0 commit comments