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文檔異步編程
首先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
拿到異步操做返回的結果
//value拿到異步操做返回的結果
//...some code
//...some code
})
另外,實例的then()方法是能夠鏈式調用的。
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
Promise.all
方法用於將多個 Promise 實例,包裝成一個新的 Promise 實例。
var p = Promise.all([p1, p2, p3]);
上面代碼中,Promise.all
方法接受一個數組做爲參數,p1
、p2
、p3
都是 Promise 實例,若是不是,就會先調用下面講到的Promise.resolve
方法,將參數轉爲 Promise 實例,再進一步處理。(Promise.all
方法的參數能夠不是數組,但必須具備 Iterator 接口,且返回的每一個成員都是 Promise 實例。)
p
的狀態由p1
、p2
、p3
決定,分紅兩種狀況。
(1)只有p1
、p2
、p3
的狀態都變成fulfilled
,p
的狀態纔會變成fulfilled
,此時p1
、p2
、p3
的返回值組成一個數組,傳遞給p
的回調函數。
(2)只要p1
、p2
、p3
之中有一個被rejected
,p
的狀態就變成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
方法後面的回調函數。
常常用到的就這幾個。