Promise的構造函數,以及被?`then`?調用執行的函數基本上都可以認為是在?`try...catch`?代碼塊中執行的,所以在這些代碼中即使使用?`throw`?,程序本身也不會因為異常而終止。
如果在Promise中使用?`throw`?語句的話,會被?`try...catch`?住,最終promise對象也變為Rejected狀態。
~~~
var promise = new Promise(function(resolve, reject){
throw new Error("message");
});
promise.catch(function(error){
console.error(error);// => "message"
});
~~~
代碼像這樣其實運行時倒也不會有什么問題,但是如果想把?[promise對象狀態](http://liubin.github.io/promises-book/#promise-states)?設置為Rejected狀態的話,使用?`reject`?方法則更顯得合理。
所以上面的代碼可以改寫為下面這樣。
~~~
var promise = new Promise(function(resolve, reject){
reject(new Error("message"));
});
promise.catch(function(error){
console.error(error);// => "message"
})
~~~
其實我們也可以這么來考慮,在出錯的時候我們并沒有調用?`throw`?方法,而是使用了?`reject`?,那么給?`reject`?方法傳遞一個Error類型的對象也就很好理解了。
## 4.3.1\. 使用reject有什么優點?
話說回來,為什么在想將promise對象的狀態設置為Rejected的時候應該使用?`reject`?而不是?`throw`?呢?
首先是因為我們很難區分?`throw`?是我們主動拋出來的,還是因為真正的其它?**異常**?導致的。
比如在使用Chrome瀏覽器的時候,Chrome的開發者工具提供了在程序發生異常的時候自動在調試器中break的功能。

Figure 12\. Pause On Caught Exceptions
當我們開啟這個功能的時候,在執行到下面代碼中的?`throw`?時就會觸發調試器的break行為。
~~~
var promise = new Promise(function(resolve, reject){
throw new Error("message");
});
~~~
本來這是和調試沒有關系的地方,也因為在Promise中的?`throw`?語句被break了,這也嚴重的影響了瀏覽器提供的此功能的正常使用。
## 4.3.2\. 在then中進行reject
在Promise構造函數中,有一個用來指定?`reject`?方法的參數,使用這個參數而不是依靠?`throw`?將promise對象的狀態設置為Rejected狀態非常簡單。
那么如果像下面那樣想在?`then`?中進行reject的話該怎么辦呢?
~~~
var promise = Promise.resolve();
promise.then(function (value) {
setTimeout(function () {
// 經過一段時間后還沒處理完的話就進行reject - 2
}, 1000);
// 比較耗時的處理 - 1
somethingHardWork();
}).catch(function (error) {
// 超時錯誤 - 3
});
~~~
上面的超時處理,需要在?`then`?中進行?`reject`?方法調用,但是傳遞給當前的回調函數的參數只有前面的一promise對象,這該怎么辦呢?
> 關于使用Promise進行超時處理的具體實現方法可以參考?[使用Promise.race和delay取消XHR請求](http://liubin.github.io/promises-book/#race-delay-timeout)?中的詳細說明。
在這里我們再次回憶下?`then`?的工作原理。
在?`then`?中注冊的回調函數可以通過?`return`?返回一個值,這個返回值會傳給后面的?`then`?或?`catch`?中的回調函數。
而且return的返回值類型不光是簡單的字面值,還可以是復雜的對象類型,比如promise對象等。
這時候,如果返回的是promise對象的話,那么根據這個promise對象的狀態,在下一個?`then`?中注冊的回調函數中的onFulfilled和onRejected的哪一個會被調用也是能確定的。
~~~
var promise = Promise.resolve();
promise.then(function () {
var retPromise = new Promise(function (resolve, reject) {
// resolve or reject 的狀態決定 onFulfilled or onRejected 的哪個方法會被調用
});
return retPromise;
}).then(onFulfilled, onRejected);
~~~
> 后面的then調用哪個回調函數是由promise對象的狀態來決定的
也就是說,這個?`retPromise`?對象狀態為Rejected的時候,會調用后面then中的?`onRejected`?方法,這樣就實現了即使在?`then`?中不使用?`throw`?也能進行reject處理了。
~~~
var onRejected = console.error.bind(console);
var promise = Promise.resolve();
promise.then(function () {
var retPromise = new Promise(function (resolve, reject) {
reject(new Error("this promise is rejected"));
});
return retPromise;
}).catch(onRejected);
~~~
使用?[Promise.reject](http://liubin.github.io/promises-book/#Promise.reject)?的話還能再將代碼進行簡化。
~~~
var onRejected = console.error.bind(console);
var promise = Promise.resolve();
promise.then(function () {
return Promise.reject(new Error("this promise is rejected"));
}).catch(onRejected);
~~~
## 4.3.3\. 總結
在本小節我們主要學習了
* 使用?`reject`?會比使用?`throw`?安全
* 在?`then`?中使用reject的方法
也許實際中我們可能不常使用?`reject`?,但是比起來不假思索的使用?`throw`?來說,使用?`reject`?的好處還是很多的。
關于上面講的內容的比較詳細的例子,大家可以參考在?[使用Promise.race和delay取消XHR請求](http://liubin.github.io/promises-book/#race-delay-timeout)?小節的介紹。
- 前言
- 第一章 - 什么是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
- 第六章 - 用語集
- 第七章 - 參考網站
- 第八章 - 關于作者
- 第九章 - 關于譯者