天天看點

小程式 ES6 Promise用法講解

一:什麼是promise

Promise 是異步程式設計的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。Promise對象是一個代理對象,一個代表未知傳回結果的對象值。這個值在Promise對象建立時可能是未知的,它允許你為異步操作的成功和失敗分别綁定相應的處理方法, 這讓異步方法可以像同步方法那樣傳回值,但并不是立即傳回最終執行結果,而是傳回一個能代表未來出現的結果的promise對象,看起來很抽象,還是用執行個體來了解吧!

二:狀态

pending:初始狀态

fulfilled:成功狀态

rejected:失敗狀态

1、fulfilled、rejected被統稱為settled,fulfilled也可被稱為resolved即為正确時走的狀态

2、隻有兩種狀态變化過程:pending → fulfilled,pending → rejected,且狀态隻可變化一次,一旦發生變化便會一直保持這個結果。

三、使用

new Promise(executor)

executor:一個帶有兩個參數(resolve和reject)的方法,resolve為fulfilled狀态,即成功之後調用,reject為rejected狀态,即失敗之後調用。

即:new Promise(function(resolve, reject){})

1、executor在建立Promise對象時立即調用

2、若executor函數中抛出錯誤,promise狀态為rejected,executor函數傳回值被忽略

先 new一個Promise,示例如下:

let p = new Promise(function (resolve, reject) {
      //做一些異步操作
      setTimeout(function () {
        console.log('執行完成Promise');
        resolve('要傳回的資料可以任何資料例如接口傳回資料');
      }, 2000);
    });
           

重新整理頁面會發現過了2秒控制台直接打出:

執行完成Promise
           

其執行過程是:執行了一個異步操作,也就是setTimeout,2秒後,輸出“執行完成”,并且調用resolve方法。在随後介紹的then方法中,可擷取resolve方法所傳回的值。

注意!我隻是new了一個對象,并沒有調用它,我們傳進去的函數就已經執行了,可放在方法中需要的時候進行調用如下所示:

onclickPromise:function(){
    console.log('放在方法中被調用')
    let p = new Promise(function (resolve, reject) {
      //做一些異步操作
      setTimeout(function () {
        console.log('執行完成Promise');
        resolve('要傳回的資料可以任何資料例如接口傳回資料');
      }, 2000);
    });
    return p;
  }
           

調用為:

this.onclickPromise();
           

四:方法

1、Promise.then(resolve[, reject])

resolve為成功回調函數,reject為失敗回調函數(可選),參數為Promise執行個體傳回值

promiseClick: function (num){
    let p = new Promise(function (resolve, reject) {
      setTimeout(function () {
        console.log('數值:', num)
        if (num <= 10) {
          resolve(num);
        }
        else {
          reject('數字大于10了即将執行失敗回調');
        }
      }, 2000);
    })
		   return p
  }
           

調用then的例子如下:

this.promiseClick(4).then(
      function (data) {
        console.log('resolved成功回調');
        console.log('成功回調接受的值:', data);
      },
      function (reason, data) {
        console.log('rejected失敗回調');
        console.log('失敗執行回調抛出失敗原因:', reason);
        console.log('失敗執行回調data是什麼:', data);
      }
    );
           

當傳入的值為4時,執行正确操作,調用resolve方法:

數值: 4
resolved成功回調
成功回調接受的值: 4
           

輸入11時執行錯誤接口調用reject方法,輸出如下:

數值: 11
rejected失敗回調
失敗執行回調抛出失敗原因: 數字大于10了即将執行失敗回調
失敗執行回調data是什麼: undefined
           

從上面的結果可知,在then方法中,放在第一位的方法表示正确時處理的方法,放在第二位的方法表示錯誤是調用的方法。

reject: (reason?: any)方法的參數可以是any,這樣在then就是傳什麼輸出什麼。resolve: (value?: any)也一樣,都是回填在then方法中的第一個參數。

promise().then().then().then() 

then支援延續任務調用方式,下面所示在第一個promiseClick1(1).then中調用promiseClick2,進入第二個then然後再調用promiseClick3

var that = this
    this.promiseClick1(1).then(
      function(data) {
        console.log('resolved成功回調');
        that.promiseClick2(3)
      }).then(
        function (data) {
          that.promiseClick3(3)
      })
           

2、Promise.catch(reject)

處理内容包括:① rejected狀态對應傳回結果,② catch方法前抛出的錯誤

this.promiseClick(11).then(
        function(data) {
          console.log('resolved成功回調');
          console.log('成功回調接受的值:', data);
        })
      .catch(function(reason, data) {
        console.log('catch到rejected失敗回調');
        console.log('catch失敗執行回調抛出失敗原因:', reason);
      });
           

錯誤的時候執行結果走catch:

數值: 11
catch到rejected失敗回調
catch失敗執行回調抛出失敗原因: 數字大于10了即将執行失敗回調
           

效果和寫在then的第二個參數裡面一樣。它将大于10的情況下的失敗回調的原因輸出,但是,它還有另外一個作用:在執行resolve的回調(也就是上面then中的第一個參數)時,如果抛出異常了(代碼出錯了),那麼并不會報錯卡死js,而是會進到這個catch方法中。如下:

this.promiseClick(4).then(
        function(data) {
          console.log('resolved成功回調');
          console.log('成功回調接受的值:', data);
          console.log(noData);

        })
      .catch(function(reason, data) {
        console.log('catch到rejected失敗回調');
        console.log('catch失敗執行回調抛出失敗原因:', reason);
      });
           

在第一個then中調用console.log(noData);方法,由于noData未定義,是以會馬上執行cath方法中,輸出如下

數值: 4
resolved成功回調
成功回調接受的值: 4
catch到rejected失敗回調
catch失敗執行回調抛出失敗原因: ReferenceError: noData is not defined
  
           

3、Promise.all([p1, p2, ... , p(n)])

p(n)(n = 1, 2, ... )均為Promise執行個體

***注:傳回Promise執行個體的狀态為rejected,即Promise執行個體的狀态為rejected,且沒有catch方法做異常處理

Promise.all([this.promiseClick3(4), this.promiseClick2(12), this.promiseClick1(11)])
      .then(function(results) {
        console.log(results);

      })
      .catch(function (reason, data) {
        console.log('catch到rejected失敗回調');
        console.log('catch失敗執行回調抛出失敗原因:', reason);
      });
  },

  promiseClick1: function(num) {
    let p = new Promise(function(resolve, reject) {
      setTimeout(function() {
        console.log('數值:', num)
        if (num <= 10) {
          resolve(num);
        } else {
          reject("promiseClick1數字大于10了即将執行失敗回調");
        }
      }, 2000);
    })
    return p
  },

  promiseClick2: function(num) {
    let p = new Promise(function(resolve, reject) {
      setTimeout(function() {
        console.log('數值:', num)
        if (num <= 10) {
          resolve(num);
        } else {
          reject("promiseClick2數字大于10了即将執行失敗回調");
        }
      }, 2000);
    })
    return p
  },

  promiseClick3: function(num) {
    let p = new Promise(function(resolve, reject) {
      setTimeout(function() {
        console.log('數值:', num)
        if (num <= 10) {
          resolve(num);
        } else {
          reject("promiseClick3數字大于10了即将執行失敗回調");
        }
      }, 2000);
    })
    return p
  }
           

① 隻有參數中所有Promise執行個體的狀态都為fulfilled,該方法傳回的Promise執行個體狀态為fulfiiled,意思為所有的都是執行resolve方法,最終才會執行正确的結果,隻要有一個是reject方法,最終都是錯誤的方法,同樣會到then裡的第二個function或者是catch中。

Promise.all([this.promiseClick3(4), this.promiseClick2(5), this.promiseClick1(6)])
      .then(function(results) {
        console.log(results);

      });
           

輸出:

數值: 4
數值: 5
數值: 6
[4, 5, 6]
           

② 參數中傳回Promise執行個體的狀态為rejected的數量大于等于1,該方法傳回的Promise執行個體狀态為rejected,傳回資料為第一個狀态變為rejected的參數方法傳回結果

Promise.all([this.promiseClick3(4), this.promiseClick2(12), this.promiseClick1(11)])
      .then(function(results) {
        console.log(results);

      })
      .catch(function (reason, data) {
        console.log('catch到rejected失敗回調');
        console.log('catch失敗執行回調抛出失敗原因:', reason);
      });
           

輸出:

數值: 4
數值: 12
catch到rejected失敗回調
catch失敗執行回調抛出失敗原因: promiseClick2數字大于10了即将執行失敗回調
數值: 11
           

4、Promise.race([p1, p2, ... , p(n)])

p(n)(n = 1, 2, ... )均為Promise執行個體

all是等所有的異步操作都執行完了再執行then方法,那麼race方法就是相反的,誰先執行完成就先執行回調。

Promise
      .race([this.promiseClick3(5), this.promiseClick2(11), this.promiseClick1(12)])
      .then(function (results) {
        console.log("第一個function:"+results);
      }, function (reason) {
        console.log("第二個function:" +reason);
      });
           

輸出:

數值: 5
第一個function:5
數值: 11
數值: 12
           

調用:

Promise
      .race([this.promiseClick3(11), this.promiseClick2(5), this.promiseClick1(12)])
      .then(function (results) {
        console.log("第一個function:"+results);
      }, function (reason) {
        console.log("第二個function:" +reason);
      });
           

輸出:

數值: 11
第二個function:promiseClick3數字大于10了即将執行失敗回調
數值: 5
數值: 12
           

從以上例子可以看出,隻會進入一個then的方法,而且是根據第一個執行的狀态進行判斷。

5:Promise.finally( )

   finally

方法用于指定不管 Promise 對象最後狀态如何,都會執行的操作

this.promiseClick1(1).then(
      function(data) {
        console.log('resolved成功回調');
        console.log('成功回調接受的值:', nodata);
      }).catch(
      function(data) {
        console.log('catch:' + data);
      }).finally(
      function(data) {
        console.log('不管過程是咋樣的,最終都會走到finally方法中');
      })
           

結果:

數值: 1
resolved成功回調
catch:ReferenceError: nodata is not defined
不管過程是咋樣的,最終都會走到finally方法中
           

6:promise.done( )

Promise 對象的回調鍊,不管以

then

方法或

catch

方法結尾,要是最後一個方法抛出錯誤,都有可能無法捕捉到(因為 Promise 内部的錯誤不會冒泡到全局)。是以,我們可以提供一個

done

方法,總是處于回調鍊的尾端,保證抛出任何可能出現的錯誤。