在?[上一章](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對象。

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
- 第六章 - 用語集
- 第七章 - 參考網站
- 第八章 - 關于作者
- 第九章 - 關于譯者