關於promise、async await 、axios的詳解


在開發項目中,我們經常需要使用ajax發起異步請求獲取數據,但是當我們需要從得到的數據中用於請求下一個異步任務時,就會有多個回調函數嵌套在里面,這個時候代碼閱讀性就會變得很差,維護成本也相對較高,這種回調函數層層嵌套我們稱之為回調地獄。

回調地獄:

$.ajax({
    url: 'data1.json',
    type: 'GET',
    success: function (res) {
        $.ajax({
            url: res.url, // 將 第一個ajax請求成功得到的res 用於第二個ajax請求
            type: 'GET',
            success: function (res) {
                $.ajax({
                    url: res.url,  // 將第二個ajax請求成功得到的res 用於第三個ajax請求
                    type: 'GET',
                    success: function (res) {
                        console.log(res)   // {url: "this is data3.json"}
                    },
                    error: function(err) {
                        console.log(err)
                    }
                })
            },
            error: function(err) {
                console.log(err)
            }
        })
    },
    error: function(err) {
        console.log(err)
    }
})

  上面出現多個回調函數的嵌套,可讀性較差,我們通常使用Promise來優化,使代碼從回調地獄中解脫出來

 

Promise:

什么是promise,在《ES6標准入門》一書中,詳細介紹了Promise

Promise是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理且強大,它最早由社區提出並實現,ES6將其寫進了語言標准,統一了用法,並原生提供了Promise對象。

Promise對象有以下兩個特點:

(1)對象的狀態不受外界影響,promise對象代表一個異步操作,有三種狀態,pending(進行中)、fulfilled(已成功)、rejected(已失敗)。只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態,這也是promise這個名字的由來“承若”;
(2)一旦狀態改變就不會再變,任何時候都可以得到這個結果,promise對象的狀態改變,只有兩種可能:從pending變為fulfilled,從pending變為rejected。這時就稱為resolved(已定型)。如果改變已經發生了,你再對promise對象添加回調函數,也會立即得到這個結果,這與事件(event)完全不同,事件的特點是:如果你錯過了它,再去監聽是得不到結果的。


關於onFulfilled、onRejected狀態,MND是這樣解釋的

onFulfilled

當Promise變成接受狀態(fulfillment)時,該參數作為回調函數被調用(參考: Function)。該函數有一個參數,即接受的最終結果(the fulfillment  value)。如果傳入的 onFulfilled 參數類型不是函數,則會在內部被替換為(x) => x ,即原樣返回 promise 最終結果的函數

onRejected

當Promise變成拒絕狀態(rejection )時,該參數作為回調函數被調用(參考: Function)。該函數有一個參數,,即拒絕的原因(the rejection reason)。

上述文檔中我們可以知道,當我們new一個Promise對象中,Promise會幫我們執行里面的異步操作,執行后的異步操作會通過Promise中resolve和reject參數傳遞出去,傳遞出去的數據我們可以在then中進行操作。

var pro0 = function (state) { return new Promise(function (resolve, reject) { if(state == true) { setTimeout(function () { resolve('第一個異步任務'); }, 1000) }else { setTimeout(function () { reject('失敗的異步任務'); }, 1000) } }) }

//當state為true時
pro0(true).then(
(data)=>{console.log(data)},//1s后輸出"第一個異步任務"
(err) =>{console.log(err)}) //未輸出

//當state為false時
pro0(false).then(
(data)=>{console.log(data)}, //"未輸出"
(err) =>{console.log(err)}) //1s后輸出"失敗的異步任務"
 

上面的代碼我們基本清楚了Promise的原理以及用法,那么Promise是怎么解決回調地獄的呢?

 

Promise鏈式調用:

事實上,Promise中的then方法除了可以接收異步請求得到的數據時,還能返回一個新的promise對象,返回來的promise對象可以接着在下一個then中進行操作,這就是所謂的鏈式調用

var pro0 = function (state) { return new Promise(function (resolve, reject) { if(state == true) { setTimeout(function () { resolve('第一個異步任務'); }, 1000) }else { setTimeout(function () { reject('失敗的異步任務'); }, 1000) } }) } var pro1 = function(){ return new Promise(function (resolve, reject) { setTimeout(function () { resolve('第二個異步任務') },1000) }) }

//當state為true時
pro0(true).then(
(data)=>{console.log(data);return pro1()},//1s后輸出"第一個異步任務"
(err) =>{console.log(err);return pro1()}//未輸出
).then((data)=>{console.log(data)})//2s后輸出"第二個異步任務"
//當state為false時
pro0(false).then(
(data)=>{console.log(data);return pro1()},//未輸出
(err) =>{console.log(err);return pro1()}//1s后輸出"失敗的異步任務"
).then((data)=>{console.log(data)})//2s后輸出"第二個異步任務"
 

上面的代碼中,我們在pro0的then里返回了一個pro1函數,在下一個then中接收到了pro1函數所傳遞出來的值

 

async await

async/await可以看做是promise中then函數的優化,then函數是鏈式調用,一點接一點,是一種從左到右的橫向寫法;而async/awiat是從上到下的順序執行,就像寫同步代碼一樣,更符合編程習慣

var pro0 = function (state) { return new Promise(function (resolve, reject) { if(state == true) { setTimeout(function () { resolve('第一個異步任務'); }, 1000) }else { setTimeout(function () { reject('失敗的異步任務'); }, 1000) } }) } var pro1 = function(){ return new Promise(function (resolve, reject) { setTimeout(function () { resolve('第二個異步任務') },1000) }) }

 async function getData () {
console.log(await pro0(true))//1s后輸出"第一個異步任務"
console.log(await pro1())//2s后輸出
}
 

上面代碼中我們為getDate()函數聲明了async,這樣當我們執行這個getData()函數的時候,里面的promise對象就會一個接一個的執行(await等待);例外,在async/await中,await只能接收resolve對象,如果想要接收reject對象,只能使用傳統的try catch去處理。

 

例外說一下axios,在實例項目開發中,我們經常使用axios配合async/await去發起異步請求處理數據,其實axios可以看作是基於promise的一種請求方式,與ajax相比,它解決了ajax回調地獄的問題,兩者的使用方式基本一樣。

axios({             url: 'xxx',             method: 'get',             responseType: 'json', // 默認的
            data: {                 //'a': 1,
                //'b': 2,
            }         }).then(function (response) {             console.log(response);             console.log(response.data);         }).catch(function (error) {             console.log(error);         }) $.ajax({             url: 'xxx',             type: 'get',             dataType: 'json',             data: {                 //'a': 1,
                //'b': 2,
            },             success: function (response) {                 console.log(response);             }         })

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM