Promise有四個靜態方法,分別是resolve()、reject()、all()和race(),本節將着重分析這幾個方法的功能和特色。數組
1)Promise.resolve()異步
此方法有一個可選的參數,參數的類型會影響它的返回值,具體可分爲三種狀況(以下所列),其中有兩種狀況會建立一個新的已處理的Promise實例,還有一種狀況會返回這個參數。async
(1)當參數爲空或非thenable時,返回一個新的狀態爲fulfilled的Promise。函數
(2)當參數爲thenable時,返回一個新的Promise,而它的狀態由自身的then()方法控制,具體細節已在以前的thenable一節作過說明。this
(3)當參數爲Promise時,將不作修改,直接返回這個Promise。spa
下面用一個例子演示這三種狀況,注意觀察Promise的then()方法的第一個回調函數中接收到的決議結果。code
let tha = { then(resolve, reject) { resolve("thenable"); } }; //參數爲空 Promise.resolve().then(function(value) { console.log(value); //undefined }); //參數爲非thenable Promise.resolve("string").then(function(value) { console.log(value); //"string" }); //參數爲thenable Promise.resolve(tha).then(function(value) { console.log(value); //"thenable" }); //參數爲Promise Promise.resolve(new Promise(function(resolve) { resolve("Promise"); })).then(function(value) { console.log(value); //"Promise" });
2)Promise.reject()對象
此方法能接收一個參數,表示拒絕理由,它的返回值是一個新的已拒絕的Promise實例。與Promise.resolve()不一樣,Promise.reject()中全部類型的參數都會原封不動的傳遞給後續的已拒絕的回調函數,以下代碼所示。blog
Promise.reject("rejected").catch(function (reason) { console.log(reason); //"rejected" }); var p = Promise.resolve(); Promise.reject(p).catch(function (reason) { reason === p; //true });
第一次調用Promise.reject()的參數是一個字符串,第二次的參數是一個Promise,catch()方法中的回調函數接收到的正是這兩個參數。事件
3)Promise.all()
此方法和接下來要講解的Promise.race()均可用來監控多個Promise,當它們的狀態發生變化時,這兩個方法會給出不一樣的處理方式。
Promise.all()能接收一個可迭代對象,其中可迭代對象中的成員必須是Promise,若是是字符串、thenable等非Promise的值,那麼會自動調用Promise.resolve()轉換成Promise。Promise.all()的返回值是一個新的Promise實例,當參數中的成員爲空時,其狀態爲fulfilled;而當參數不爲空時,其狀態由可迭代對象中的成員決定,具體分爲兩種狀況。
(1)當可迭代對象中的全部成員都是已完成的Promise時,新的Promise的狀態爲fulfilled。而各個成員的決議結果會組成一個數組,傳遞給後續的已完成的回調函數,以下所示。
var p1 = Promise.resolve(200), p2 = "fulfilled"; Promise.all([p1, p2]).then(function (value) { console.log(value); //[200, "fulfilled"] });
(2)當可迭代對象中的成員有一個是已拒絕的Promise時,新的Promise的狀態爲rejected。而且只會處理到這個已拒絕的成員,接下來的成員都會被忽略,其決議結果會傳遞給後續的已拒絕的回調函數,以下所示。
var p1 = Promise.reject("error"), p2 = "fulfilled"; Promise.all([p1, p2]).catch(function (reason) { console.log(reason); //"error" });
4)Promise.race()
此方法和Promise.all()有不少類似的地方,以下所列。
(1)能接收一個可迭代對象。
(2)成員必須是Promise,對於非Promise的值要用Promise.resolve()作轉換。
(3)返回值是一個新的Promise實例。
新的Promise實例的狀態也與方法的參數有關,當參數的成員爲空時,其狀態爲pending;當參數不爲空時,其狀態是最早被處理的成員的狀態,而且此成員的決議結果會傳遞給後續相應的回調函數,以下代碼所示。
var p1 = new Promise(function(resolve) { setTimeout(() => { resolve("fulfilled"); }, 200); }); var p2 = new Promise(function(resolve, reject) { setTimeout(() => { reject("rejected"); }, 100); }); Promise.race([p1, p2]).catch(function (reason) { console.log(reason); //"rejected" });
在p1和p2的執行器中都有一個定時器。因爲後者的定時器會先執行,所以經過調用Promise.race([p1, p2])獲得的Promise實例,其狀態和p2的相同,而p2的決議結果會做爲拒絕理由被catch()方法中的回調函數接收。
根據前面的分析能夠得出,Promise.all()能處理一個或多個受監控的Promise,而Promise.race()只能處理其中的一個。
1)Promise和生成器
用Promise和生成器實現一個運行器,能夠取代冗長的Promise鏈,以一種更直觀的方式控制異步,相似於下面這樣。
function load() { return new Promise(function(resolve, reject) { resolve("success"); }); } run(function* () { var result = yield load(); console.log(result); //"success" });
在load()函數內部,執行的是異步操做,因爲處在run運行器中,所以它的決議結果可經過賦值語句直接給到result。這種工做模式徹底顛覆了過去用回調函數接收異步操做結果的模式。爲此,ES8規範特意引入了兩個關鍵字:async和await,支持這種便捷的工做模式,下面改寫上一個示例,用新語法實現相同的功能。
(async function() { var result = await load(); console.log(result); //"success" })();
關於run運行器的工做原理和ES8的新語法,限於篇幅緣由,此處再也不展開說明。
2)與傳統異步操做的組合
以往須要用回調函數接收異步處理結果的操做,如今都能改爲Promise的模式。以圖像加載爲例,當圖像載入成功時,會觸發load事件;而當失敗時,會觸發error事件。若是後續又有異步操做,那麼就只能在這兩個事件中處理,但這麼一來,就會造成難以控制的回調金字塔。而改用Promise後,就能鏈式的處理後續的操做,以下所示。
function preImg(src) { return new Promise(function (resolve, reject) { var img = new Image(); img.src = src; img.onload = function(){ resolve(this); }; img.onerror = function(){ reject(this); }; }); }; preImg("img/page.png").then(function(value) { console.log(value); });