1. 程式人生 > 實用技巧 >Promise學習筆記(一)

Promise學習筆記(一)

前言

一開始學習前端的時候,很多技術都是學習其用法,實際上很少去了解其原理,因此在空閒時,去寫一些筆記記錄一下自己對一些常用技術的原理理解。

什麼是Promise?

Promise 是ES6提供的一個物件,Promise物件代表了未來將要發生的事件,用來傳遞非同步操作的訊息;常用在網路請求中。

Promise物件的狀態不受外界影響,它有三種狀態

  ·pending 進行中

  ·fulfilled 已成功

  ·rejected 已失敗

Promise的狀態只能由非同步操作的結果決定。並且,Promise物件的狀態既定,便不會再發生改變,且任何時候都能夠得到其結果。Promise的狀態改變通常只有 pending——fulfulled || pending——rejected。

Promise的優缺點

Promise物件可以將非同步操作以同步操作的流程表達出來,避免了層層巢狀的回撥函式。而且Promise物件提供了統一的介面,使得控制非同步操作更加容易。

但是,Promise一旦新建就會立即執行,中途是無法取消的。其次,若不設定回撥函式,Promise內部丟擲的錯誤,是不會反應到外部(由於它內部不會受到外部的影響)。當Promise物件處於pending狀態時,是無法得知目前進展到哪一個階段。

Promise基礎使用

使用一個東西的時候,我們常常需要了解這個東西內部提供了什麼給我呼叫,所以先看一下Promise。

通過列印可以看出來,Promise是一個建構函式,它本身有all、reject、resolve方法,原型上還有then、catch等方法。所以想要建立一個Promise,使用new關鍵字即可。

let pro = new Promise (function (resolve, reject) {

    setTimeout (function () {
        console.log('Promise執行完畢')
        resolve('返回資料,通知回撥執行')
    }, 1000)
})

Promise的建構函式接收一個函式作為引數,函式傳入了兩個引數,分別為 resoleve 和 reject,前者代表了非同步操作成功(pending—fulfilled)的回撥函式,後者代表了非同步操作失敗(pending—rejected)的回撥函式。

上面的程式碼,執行了一個非同步操作,也就是定時器,在1秒後,輸出“Promise執行完畢”,並且呼叫resolve方法。

實際上,當我們使用new關鍵字建立Promise物件時,被當做引數的函式傳進去的時候已經執行了。所以我們使用Promise的時候,一般當做變數存放在一個函式中,在需要的時候再去執行這個函式。

function go () {
    let pro = new Promise (function (resolve, reject) {

        setTimeout (function () {
            console.log('Promise執行完畢')
            resolve('返回資料,通知回撥執行')
        }, 1000)
    })

    return pro
}

那再看回來,為什麼我們要把Promise包在函式中,還有就是resolve在這裡面是什麼作用。

上面的截圖中,我們知道了Promise實際上是一個建構函式,可以呼叫then、catch方法。當我們將Promise包在函式中,我們可以這樣使用

function go () {
    let pro = new Promise (function (resolve, reject) {

        setTimeout (function () {
            console.log('Promise執行完畢')
            resolve('返回資料,通知回撥執行')
        }, 1000)
    })

    return pro
}

go().then(function(data){
    console.log('在這執行後續的操作,data是resolve傳遞的引數')
})

看了上面這段程式碼,就懂了,then裡面的函式實際上差不多是我們平時使用的回撥函式。這個時候,可能會有個疑惑,既然這樣子的用法,跟我們平時呼叫方法再寫回調函式沒什麼區別,為什麼還要大費周折地去用Promise?那再往回調裡去想,如果有多層回撥,而且回撥本身也是一個非同步操作呢?如果按照傳統的寫法來處理,會進入回撥地獄,後期維護成本會很大,維護難度高,而Promise可以在then中繼續寫Promise物件並返回,然後繼續呼叫then來進行回撥操作,可以避免上述問題。

看到這裡,我們似乎忘記了什麼,emmmm..... 就是reject。那我們看一下下面的程式碼,很容易就理解了,這裡使用一段ajax請求來寫。

function ajax(URL) {
    return new Promise(function (resolve, reject) {
        var req = new XMLHttpRequest(); 
        req.open('GET', URL, true);
        req.onload = function () {
            if (req.status === 200) { 
                resolve(req.responseText);
            } else {
                reject(new Error(req.statusText));
            } 
        };
        req.onerror = function () {
            reject(new Error(req.statusText));
        };
        req.send(); 
    });
}

var URL = "請求地址"; 
ajax(URL).then(
    function success(data){
        console.log('resolve') 
    },
    function fail(reason, data) {
        console.log('reject')
    }
)

請求成功時,我們會用resolve傳遞成功的返回值去進行回撥操作,失敗或者出現異常時,則使用reject傳遞引數。在程式碼中,可以看到,then方法中接收了兩個函式作為引數,第一個為resolve的回撥,第二個為reject的回撥。

上述則是個人對於Promise基礎使用的一些心得。