ES6中的Promise對象

什麼是Promise對象?

Promise是異步編程的一種解決方案,比起傳統的解決方案(回調函數和事件),它顯得更加的強大和方便(具體請看下文)。從語法上來說,Promise是一個對象,從它能夠獲取異步操做的消息。Promise對象提供統一的API,各類異步操做均可以用一樣的方法進行處理。node

Promise有什麼用?

你們一致會回答,解決回調地獄。那什麼又是回調地獄?它有什麼缺點?es6

若是要執行四個步驟,依次執行,那麼傳統咱們可能會這麼作:ajax

step1(function (value1) {
    step2(value1, function(value2) {
        step3(value2, function(value3) {
            step4(value3, function(value4) {
                // Do something with value4
            });
        });
    });
});
複製代碼

爲了解決這種看起來不很舒服,寫起來更不舒服的寫法,咱們可能會想起鏈式寫法:編程

var obj = {
    stepOne: function () {
        console.log('one');
        return this;
    },
    stepTwo: function () {
        console.log('two');
        return this;
    },
    stepThree: function () {
        console.log('three');
        return this;
    }
}

obj.stepOne().stepThree().stepTwo();
複製代碼

這種寫法的核心在於,每次都返回this。 這樣的好處在於:json

  • 每個操做都是獨立的一個函數
  • 能夠組裝,也就是咱們能夠控制執行的流程

那若是咱們還須要一些其餘需求的時候呢?好比:數組

  • 若是上一步的結果做爲下一步的輸入就更好了
  • 若是出錯我可以捕捉就更好了
  • 若是我在函數中可以控制流程就行了 ....

這個時候,就須要用到咱們強大的Promise了promise

基礎用法

先來看看怎麼使用吧!直接上代碼:bash

const p1 = new Promise(function(resolve, reject) {
    // 在這裏作一些邏輯處理
    // 若是異步操做成功的時候,調用resolve
    if (true) {
        resolve('success');
    } else {
        // 操做失敗後咱們就調用reject()
        reject('fail');
    }
})

p1.then((val) => {
    console.log(val); // success
}, (err) => {
    console.log(err)
})
複製代碼

咱們能夠看到Promise是一個構造函數,用來生成Promise實例,它接收一個函數做爲參數,這個函數有兩個參數——resolve和reject(它們也是兩個函數,已經由JavaScript引擎提供,不用本身部署)。異步

咱們常常會在這個函數裏處理一些邏輯,若是處理成功後咱們會執行resolve(將狀態從「未完成」轉爲「完成」),失敗後執行reject(將狀態從「未完成」轉換爲「失敗」)。異步編程

三個狀態

  • pedding(未完成)
  • resolved(完成)
  • rejected(失敗)

實例生成以後,咱們可使用then方法指定resolved和rejected狀態的回調函數。像上面的代碼,就至關於執行第一個回調函數,第二個不會執行(這個時候其實不提供第二個參數也是能夠的)。

若是是執行失敗,狀態變成reject的時候,就會執行第二個回調函數,就會輸出'fail'。可是其實咱們不是很推薦這樣的寫法,咱們能夠將第二個回調函數寫catch方法的形式。

const p1 = new Promise(function(resolve, reject) {
    // 在這裏作一些邏輯處理
    // 若是異步操做成功的時候,調用resolve
    if (false) {
        resolve('success');
    } else {
        // 操做失敗後咱們就調用reject()
        reject('fail');
    }
})

p1.then((val) => {
    console.log(val);
}).catch((err) => {
    console.log(err); // fail
})
複製代碼

這種寫法相似於try...catch...,更加易於咱們理解。這個時候咱們其實就已經解決了出錯咱們可以捕捉的問題了。

控制代碼的執行順序

採用鏈式的then,能夠指定一組按照次序調用的回調函數。這個時候前面的一個返回的多是另一個Promise對象(也就是說有異步操做)。這樣後面的這個Promise就依賴於前面Promise對象的狀態。

const p1 = new Promise(function(resolve, reject) {
    console.log(1);
    setTimeout(function() {
        console.log(2);
        resolve();
    }, 1000);
})

const p2 = new Promise(function(resolve, reject) {
    console.log(3);
    resolve(p1);
})

p2.then(() => {
    console.log(4);
}).then(() => {
    console.log(5);
})
複製代碼

輸出結果

以上代碼,咱們應該注意一點p2的resolve方法將p1做爲參數,也就是說p2的執行依賴於p1的執行。當p2準備好的時候,p1可能還沒準備好,這個時候p2就得等p1。

另外,須要注意的一點就是,then方法返回的是一個新的Promise實例(注意,不是以前的Promise實例),所以能夠採用鏈式寫法,即then方法以後再調用另外一個then方法。這樣,咱們就能夠實現了上面的需求了!

Promise的幾個重要方法

下面簡單介紹一下Promise對象的幾個方法,咱們常常也會用到。

Promise.all()

直接上代碼:

const p = Promise.all([p1, p2, p3]);
複製代碼

Promise.all方法接收一個數組做爲參數,p一、p二、p3都是Promise實例。這個時候p的狀態由p一、p二、p3。它們的依賴機制相似於電路中的串聯,如今咱們使用三條線(就是p一、p二、p3)進行串聯,p就是最後燈泡,燈泡要亮的話,三個都要成功,只要其中的一個沒有成功,那麼p的狀態就是rejected。

Promise.race()

const p = Promise.race([p1, p2, p3]);
複製代碼

這個方法也是接受一個數組做爲參數。race的英文意思就有競賽的意思。上面的代碼中表示,p一、p二、p3中哪一個勝出(最新狀態發生改變,無論是失敗仍是成功),那麼p的狀態就會跟着它改變。

Promise.resolve()

做用:將現有對象轉換成Promise對象,這樣咱們就能夠調用then方法等

const jsPromise = Promise.resolve($.ajax('/whatever.json'));
複製代碼

Promise.reject()

Promise.reject(reason)方法也會返回一個Promise實例,該實例狀態爲rejected。

const p = Promise.reject('出錯了');
// 等同於
const p = new Promise((resolve, reject) => reject('出錯了'))

p.then(null, function (s) {
  console.log(s)
});
// 出錯了
複製代碼

參考: https://cnodejs.org/topic/560dbc826a1ed28204a1e7de

http://es6.ruanyifeng.com/#docs/promise

相關文章
相關標籤/搜索