深刻淺出理解Promise

1.Promise 的含義

Promise 是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。它由社區最先提出和實現,ES6 將其寫進了語言標準,統一了用法,原生提供了Promise對象。javascript

所謂Promise,簡單說就是一個容器,裏面保存着某個將來纔會結束的事件(一般是一個異步操做)的結果。從語法上說,Promise 是一個對象,從它能夠獲取異步操做的消息。Promise 提供統一的 API,各類異步操做均可以用一樣的方法進行處理。java

Promise對象有如下兩個特色。es6

(1)對象的狀態不受外界影響。Promise對象表明一個異步操做,有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)。只有異步操做的結果,能夠決定當前是哪種狀態,任何其餘操做都沒法改變這個狀態。這也是Promise這個名字的由來,它的英語意思就是「承諾」,表示其餘手段沒法改變。編程

(2)一旦狀態改變,就不會再變,任什麼時候候均可以獲得這個結果。Promise對象的狀態改變,只有兩種可能:從pending變爲fulfilled和從pending變爲rejected。只要這兩種狀況發生,狀態就凝固了,不會再變了,會一直保持這個結果,這時就稱爲 resolved(已定型)。若是改變已經發生了,你再對Promise對象添加回調函數,也會當即獲得這個結果。這與事件(Event)徹底不一樣,事件的特色是,若是你錯過了它,再去監聽,是得不到結果的。json

注意,爲了行文方便,本章後面的resolved統一隻指fulfilled狀態,不包含rejected狀態。數組

有了Promise對象,就能夠將異步操做以同步操做的流程表達出來,避免了層層嵌套的回調函數。此外,Promise對象提供統一的接口,使得控制異步操做更加容易。promise

Promise也有一些缺點。首先,沒法取消Promise,一旦新建它就會當即執行,沒法中途取消。其次,若是不設置回調函數,Promise內部拋出的錯誤,不會反應到外部。第三,當處於pending狀態時,沒法得知目前進展到哪個階段(剛剛開始仍是即將完成)。異步

詳細請參考ES6文檔異步編程

2.基本用法

首先Promise對象是一個構造函數,使用它須要用new一個promise實例:函數

 1)var promise = new Promise(function(resolve, reject) {

  // ... some code這裏邊是咱們具體實現的異步操做邏輯 if (/* 異步操做成功 */){ resolve(value); } else { reject(error); } });

另外,promise對象返回的能夠是數值,也能夠是一個promise實例。
var p1 = new Promise(function (resolve, reject) {  // ... }); var p2 = new Promise(function (resolve, reject) {  // ... resolve(p1); })


2)實例化promise對象以後,咱們就能夠用對象的實例方法then()來處理異步操做返回的結果。
promise.then( value=>{
//value拿到異步操做返回的結果
//...some code
//value拿到異步操做返回的結果
//...some code
})
另外,實例的then()方法是能夠鏈式調用的。

3.Promise.prototype.catch() 

Promise.prototype.catch方法是.then(null, rejection)的別名,用於指定發生錯誤時的回調函數。

通常來講,不要在then方法裏面定義Reject狀態的回調函數(即then的第二個參數),老是使用catch方法。

通常老是建議,Promise 對象後面要跟catch方法,這樣能夠處理 Promise 內部發生的錯誤。catch方法返回的仍是一個 Promise 對象,所以後面還能夠接着調用then方法。



var someAsyncThing = function() { return new Promise(function(resolve, reject) { // 下面一行會報錯,由於x沒有聲明 resolve(x + 2); }); }; someAsyncThing() .catch(function(error) { console.log('oh no', error); }) .then(function() { console.log('carry on'); }); // oh no [ReferenceError: x is not defined] // carry on

4.Promise.all()

Promise.all方法用於將多個 Promise 實例,包裝成一個新的 Promise 實例。

var p = Promise.all([p1, p2, p3]); 

上面代碼中,Promise.all方法接受一個數組做爲參數,p1p2p3都是 Promise 實例,若是不是,就會先調用下面講到的Promise.resolve方法,將參數轉爲 Promise 實例,再進一步處理。(Promise.all方法的參數能夠不是數組,但必須具備 Iterator 接口,且返回的每一個成員都是 Promise 實例。)

p的狀態由p1p2p3決定,分紅兩種狀況。

(1)只有p1p2p3的狀態都變成fulfilledp的狀態纔會變成fulfilled,此時p1p2p3的返回值組成一個數組,傳遞給p的回調函數。

(2)只要p1p2p3之中有一個被rejectedp的狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調函數。

下面是一個具體的例子。

// 生成一個Promise對象的數組 var promises = [2, 3, 5, 7, 11, 13].map(function (id) { return getJSON('/post/' + id + ".json"); }); Promise.all(promises).then(function (posts) {  // ... }).catch(function(reason){  // ... }); 

上面代碼中,promises是包含6個 Promise 實例的數組,只有這6個實例的狀態都變成fulfilled,或者其中有一個變爲rejected,纔會調用Promise.all方法後面的回調函數。

 

常常用到的就這幾個。

相關文章
相關標籤/搜索