Promise API 概述
new Promise(..) 構造器
有啟示性的構造器Promise(..) 必須和new 一起使用,并且必須提供一個函數回調。這個回調是同步的或立即調用的。這個函數接受兩個函數回調,用以支持promise 的決議。通常我們把這兩個函數稱為resolve(..) 和reject(..):
var p = new Promise(function(resolve, reject) {
// resolve(..)用于決議/完成這個promise
// reject(..)用于拒絕這個promise
});
reject(..) 就是拒絕這個promise;但resolve(..) 既可能完成promise,也可能拒絕,要根據傳入參數而定。如果傳給resolve(..) 的是一個非Promise、非thenable 的立即值,這個promise 就會用這個值完成。
但是,如果傳給resolve(..) 的是一個真正的Promise 或thenable 值,這個值就會被遞歸展開,并且(要構造的)promise 將取用其最終決議值或狀態。
Promise.resolve(..) 和Promise.reject(..)
創建一個已被拒絕的Promise 的快捷方式是使用Promise.reject(..),所以以下兩個promise 是等價的:
var p1 = new Promise(function(resolve, reject) {
reject("Oops");
});
var p2 = Promise.reject("Oops");
Promise.resolve(..) 常用于創建一個已完成的Promise,使用方式與Promise.reject(..)類似。但是,Promise.resolve(..) 也會展開thenable 值(前面已多次介紹)。在這種情況下,返回的Promise 采用傳入的這個thenable 的最終決議值,可能是完成,也可能是拒絕:
var fulfilledTh = {
then: function(cb) {
cb(42);
}
};
var rejectedTh = {
then: function(cb, errCb) {
errCb("Oops");
}
};
var p1 = Promise.resolve(fulfilledTh);
var p2 = Promise.resolve(rejectedTh);
// p1是完成的promise
// p2是拒絕的promise
還要記住,如果傳入的是真正的Promise,Promise.resolve(..) 什么都不會做,只會直接把這個值返回。所以,對你不了解屬性的值調用Promise.resolve(..),如果它恰好是一個真正的Promise,是不會有額外的開銷的。
then(..) 和catch(..)
每個Promise 實例(不是Promise API 命名空間)都有then(..) 和catch(..) 方法,通過這兩個方法可以為這個Promise 注冊完成和拒絕處理函數。Promise 決議之后,立即會調用這兩個處理函數之一,但不會兩個都調用,而且總是異步調用。
then(..) 接受一個或兩個參數:第一個用于完成回調,第二個用于拒絕回調。如果兩者中的任何一個被省略或者作為非函數值傳入的話,就會替換為相應的默認回調。默認完成回調只是把消息傳遞下去,而默認拒絕回調則只是重新拋出(傳播)其接收到的出錯原因。
p.then( fulfilled );
p.then( fulfilled, rejected );
p.catch( rejected ); // 或者p.then( null, rejected )
Promise 局限性
順序錯誤處理
Promise 的設計局限性(具體來說,就是它們鏈接的方式)造成了一個讓人很容易中招的陷阱,即Promise 鏈中的錯誤很容易被無意中默默忽略掉。
單一值
根據定義,Promise 只能有一個完成值或一個拒絕理由。在簡單的例子中,這不是什么問題,但是在更復雜的場景中,你可能就會發現這是一種局限了。
一般的建議是構造一個值封裝(比如一個對象或數組)來保持這樣的多個信息。這個解決方案可以起作用,但要在Promise 鏈中的每一步都進行封裝和解封,就十分丑陋和笨重了。
其他promise知識點省略。