ES6的Promise:要優雅,也要浪漫

在ECMAScript 6標準中,Promise被正式列爲規範,Promise,字面意思就是「許諾,承諾」,嘿,聽着是否是很浪漫的說?咱們來探究一下這個浪漫的Promise對象究竟是如何許下承諾,又是如何兌現TA的諾言的。git

1.許下一個Promise(承諾)

下面咱們將經過一些簡單的例子,來一步一步的探究Promise的含義,更重要的是,用心體會Ta的優雅和浪漫(PS:讓程序猿體會浪漫,是否是難爲你們了)es6

在ES6標準中被定義爲一個構造函數,那好咱們就先new一個對象出來看看。github

var promise = new Promise(function(resolve,reject){
   //一個異步操做
    setTimeout(function(){
        let foo = 1;
        console.log('執行完成');
        resolve(foo);
    }, 2000);
});

上面的代碼就能夠看做是Promise給咱們許下了一個承諾,不過,這特麼究竟是個啥意思呢?
構造函數Promise接收一個回調函數作參數,同時這個回調函數又接受2個function作參數,本例中分別起名叫resolvereject,分別表明異步操做執行成功後的操做,和異步操做執行失敗後的操做
ES6標準中規定一個 Promise的當前狀態必須爲如下三種狀態中的一種:數組

  • 進行中(Pendingpromise

  • 已完成(ResolvedFulfilled瀏覽器

  • 已失敗(Rejected異步

下表簡單總結了三種狀態所表明的含義:函數

名稱 含義 知足條件
Pending 進行中 操做正在執行,能夠切換爲Resolve或Rejected狀態
Resolved 已完成 必須擁有一個不可變的終值,且不能夠切換到其餘狀態
Rejected 已失敗 必須擁有一個不可變的終值,且不能夠切換到其餘狀態

當Promise的狀態由pending狀態,經過resolve函數改變爲resolved,或者經過reject函數改變爲rejected後,狀態就凝固了,不會再變了,會一直保持這個結果。就算改變已經發生了,即便再對Promise對象添加回調函數,也會當即獲得這個結果。學習

2.兌現你的承諾

最重要的不是看Ta怎麼說,重要的是要看Ta怎麼作。既然許下了承諾,就必需要兌現承諾。
下面就要介紹Promise.prototype.then()方法,來訪問其當前值、終值和據因。它的做用是爲Promise實例添加狀態改變時的回調函數then方法接收2個參數,第一個參數是Resolved狀態的回調函數,第二個參數(可選)是Rejected狀態的回調函數。
廢話很少說直接上示例代碼:網站

function foo (a){
  var promise = new Promise(function(resolve,reject){
      setTimeout(function(){
          if(a > 0){
            resolve(a);
          }else {
            reject(a);
          }
      }, 2000);
  });
  return promise;
}

foo(1).then(function(a){
  console.log("success",a+1);
},function(a){
  console.log("error",a);
});

上面的代碼中,簡單設定一個定時任務模擬異步操做,當a>0時,認爲操做成功,則在then方法中執行第一個回調函數,輸出success;當傳入的值 a<0時,就被認爲操失敗,則then方法執行第二個回調函數,輸出error。看到這裏,咱們可能會感受到Promise 和咱們以前用的回調函數有點類似,可是貌似Promise是用同步的寫法來處理異步的操做。簡單來說,Promise就是能把原來的回調寫法分離出來,在異步操做執行完後,用鏈式調用的方式執行回調函數。
咱們瞭解了以上的基本原理,之後碰到須要傳遞多個callback的狀況的時候,就可使用Promise實現鏈式調用,從而避免陷入回調地獄中。
示例代碼:

function foo(a) {
  ++a;
  console.log(a);
  var promise = new Promise(function (resolve, reject) {
    setTimeout(function () {
      if (a > 0) {
        resolve(a);
      } else {
        reject(a);
      }
    }, 2000);
  });
  return promise;
}
function foo2(a) {
  ++a;
  console.log(a);
  var promise = new Promise(function (resolve, reject) {
    setTimeout(function () {
      if (a > 1) {
        resolve(a);
      } else {
        reject(a);
      }
    }, 2000);
  });
  return promise;
}
function foo3(a) {
  ++a;
  console.log(a);
  var promise = new Promise(function (resolve, reject) {
    setTimeout(function () {
      if (a > 2) {
        resolve(a);
      } else {
        reject(a);
      }
    }, 2000);
  });
  return promise;
}
function foo4(a) {
  ++a;
  console.log(a);
  var promise = new Promise(function (resolve, reject) {
    setTimeout(function () {
      if (a > 3) {
        resolve(a);
      } else {
        reject(a);
      }
    }, 2000);
  });
  return promise;
}

//鏈式調用各個處理函數
foo(1).then(function (a) {
  return foo2(a);
})
.then(function (a) {
  return foo3(a);
})
.then(function (a) {
  return foo4(a);
})

3.承諾兌現不了咋辦

並非全部的承諾都會被兌現,就好像小時候父母都說幫咱們存壓歲錢之後還給咱們同樣。Promise中也是如此,總會有咱們意想不到的差錯發生致使沒法按照預期的函數進行執行,
因此Promise提供了一個名爲catch的方法幫咱們解決這個問題。
Promise.prototype.catch()方法有2個做用,第一個做用,就是和then方法中的第二個參數做用相同,就是當狀態切換成rejected時執行相應的操做,例如第一個例子中換個寫法:

foo(1)
.then(function(a){
  console.log("success",a+1);
})
.catch(function(a){
  console.log("error",a);
});

做用和原來徹底一致。
第二個做用就是在執行resolve的回調(也就是上面then中的第一個參數)時,若是拋出異常了(代碼出錯了),那麼並不會報錯卡死js,而是會進到這個catch方法中。

4.玩兒了命也要兌現承諾

要是你在生活中真遇到一個肯爲你玩兒命的人。。。。。
關我毛事,勞資單身狗,秀恩愛的請移步他處。。。。。
Promise中提供了Promise.all方法,注意all方法是直接定義在Promise上的而不是原型鏈中。主要做用就是提供了並行執行異步操做的能力,讓程序玩了命的跑起來。

var promise = Promise.all([p1, p2, p3]).then(function (p) {
  console.log(p);
});

Promise.all會將多個Promise的實例,包裝成一個新的Promise實例,而後傳遞給後面的then方法。

Promise.all方法的參數能夠不是數組,但必須具備Iterator接口,且返回的每一個成員都是Promise實例

兼容性

說了這麼多,哇塞這麼優雅的特性必定要用起來啊,可是在激動之餘,畢竟Promise是ES6標準中的新增對象,因此仍是得冷靜下來檢查一下Promise對象的兼容性如何,
Promise兼容性
經過在can I use...網站上獲取到的統計數據看來,Promise對象的兼容性不是很好,目前只有在比較新的主流瀏覽器中才獲得全面支持,並且咱們注意到微軟的全部IE瀏覽器均不支持該對象,只有在win10中的Edge瀏覽器中才得到支持。看來咱們在準備使用Promise的時候,仍是要視本身的實際開發環境而定。

關於ES6的其餘特性的最新支持狀況,請點擊這裏

總結

Promise做爲ES6標準中一個比較新鮮的特性,還有其餘方法這裏沒有講到,好比resolve,reject,race等,受限於水平與時間精力,今天暫時先寫這麼多,之後有時間再繼續補充,對於文中的錯誤和不足,歡迎你們指出討論,共同窗習進步(雖然我不必定看。。。。逃。。)

附:在GitHub上閱讀請點擊

相關文章
相關標籤/搜索