在 [上一章](http://liubin.github.io/promises-book/#catch-as-alias) 里,我们说过 [`.catch`](http://liubin.github.io/promises-book/#promise.catch) 也可以理解为 `promise.then(undefined, onRejected)` 。
在本书里我们还是会将 [`.catch`](http://liubin.github.io/promises-book/#promise.catch) 和 [`.then`](http://liubin.github.io/promises-book/#promise.then) 分开使用来进行错误处理的。
此外我们也会学习一下,在 `.then` 里同时指定处理对错误进行处理的函数相比,和使用 `catch` 又有什么异同。
## 2.10.1\. 不能进行错误处理的onRejected
我们看看下面的这段代码。
then-throw-error.js
~~~
function throwError(value) {
// 抛出异常
throw new Error(value);
}
// <1> onRejected不会被调用
function badMain(onRejected) {
return Promise.resolve(42).then(throwError, onRejected);
}
// <2> 有异常发生时onRejected会被调用
function goodMain(onRejected) {
return Promise.resolve(42).then(throwError).catch(onRejected);
}
// 运行示例
badMain(function(){
console.log("BAD");
});
goodMain(function(){
console.log("GOOD");
});
~~~
在上面的代码中, `badMain` 是一个不太好的实现方式(但也不是说它有多坏), `goodMain` 则是一个能非常好的进行错误处理的版本。
为什么说 `badMain` 不好呢?,因为虽然我们在 `.then` 的第二个参数中指定了用来错误处理的函数,但实际上它却不能捕获第一个参数 `onFulfilled` 指定的函数(本例为 `throwError` )里面出现的错误。
也就是说,这时候即使 `throwError` 抛出了异常,`onRejected` 指定的函数也不会被调用(即不会输出"BAD"字样)。
与此相对的是, `goodMain` 的代码则遵循了 `throwError`→`onRejected` 的调用流程。 这时候 `throwError` 中出现异常的话,在会被方法链中的下一个方法,即 `.catch` 所捕获,进行相应的错误处理。
`.then` 方法中的onRejected参数所指定的回调函数,实际上针对的是其promise对象或者之前的promise对象,而不是针对 `.then` 方法里面指定的第一个参数,即onFulfilled所指向的对象,这也是 `then` 和 `catch` 表现不同的原因。
> `.then` 和 `.catch` 都会创建并返回一个 **新的** promise对象。 Promise实际上每次在方法链中增加一次处理的时候所操作的都不是完全相同的promise对象。
![Then Catch flow](https://box.kancloud.cn/2015-07-20_55ac74973a311.png)
Figure 6\. Then Catch flow
这种情况下 `then` 是针对 `Promise.resolve(42)` 的处理,在`onFulfilled` 中发生异常,在同一个 `then` 方法中指定的 `onRejected` 也不能捕获该异常。
在这个 `then` 中发生的异常,只有在该方法链后面出现的 `catch` 方法才能捕获。
当然,由于 `.catch` 方法是 `.then` 的别名,我们使用 `.then` 也能完成同样的工作。只不过使用 `.catch` 的话意图更明确,更容易理解。
~~~
Promise.resolve(42).then(throwError).then(null, onRejected);
~~~
## 2.10.2\. 总结
这里我们又学习到了如下一些内容。
1. 使用`promise.then(onFulfilled, onRejected)` 的话
* 在 `onFulfilled` 中发生异常的话,在 `onRejected` 中是捕获不到这个异常的。
2. 在 `promise.then(onFulfilled).catch(onRejected)` 的情况下
* `then` 中产生的异常能在 `.catch` 中捕获
3. [`.then`](http://liubin.github.io/promises-book/#promise.then) 和 [`.catch`](http://liubin.github.io/promises-book/#promise.catch) 在本质上是没有区别的
* 需要分场合使用。
我们需要注意如果代码类似 `badMain` 那样的话,就可能出现程序不会按预期运行的情况,从而不能正确的进行错误处理。
- 前言
- 第一章 - 什么是Promise
- 1.1. 什么是Promise
- 1.2. Promise简介
- 1.3. 编写Promise代码
- 第二章 - 实战Promise
- 2.1. Promise.resolve
- 2.2. Promise.reject
- 2.3. 专栏: Promise只能进行异步操作?
- 2.4. Promise#then
- 2.5. Promise#catch
- 2.6. 专栏: 每次调用then都会返回一个新创建的promise对象
- 2.7. Promise和数组
- 2.8. Promise.all
- 2.9. Promise.race
- 2.10. then or catch?
- 第三章 - Promise测试
- 3.1. 基本测试
- 3.2. Mocha对Promise的支持
- 3.3. 编写可控测试(controllable tests)
- 第四章 - Advanced
- 4.1. Promise的实现类库(Library)
- 4.2. Promise.resolve和Thenable
- 4.3. 使用reject而不是throw
- 4.4. Deferred和Promise
- 4.5. 使用Promise.race和delay取消XHR请求
- 4.6. 什么是 Promise.prototype.done ?
- 4.7. Promise和方法链(method chain)
- 4.8. 使用Promise进行顺序(sequence)处理
- 第五章 - Promises API Reference
- 5.1. Promise#then
- 5.2. Promise#catch
- 5.3. Promise.resolve
- 5.4. Promise.reject
- 5.5. Promise.all
- 5.6. Promise.race
- 第六章 - 用語集
- 第七章 - 参考网站
- 第八章 - 关于作者
- 第九章 - 关于译者