javascript

Promise入門之基本用法

背景在我們使用非同步函式比如ajax進行編寫程式碼,如果我們需要很多個ajax請求不同的介面,而下一個介面需要...

>

背景

在我們使用非同步函式比如ajax進行編寫程式碼,如果我們需要很多個ajax請求不同的介面,而下一個介面需要依賴上一個介面的返回值,這樣,我們的程式碼則需要在各種回撥函式中巢狀,這樣一層一層地下去,就形成了回撥地獄。

但是promise的出現則不需要巢狀就能解決這個問題。什麼是promise?promise本質其實是一個物件,用於傳遞非同步操作的資訊。並且promise這個物件提供了相對應的API,滿足我們的需求開發。

建立promise物件

let pro = new Promise(function(resolve, reject){
    // 非同步處理邏輯
    // 處理完畢之後呼叫resolve或者reject
})

promise物件跟其他普通物件的建立方法一樣,只需要new一個新的物件即可,接受一個函式作為引數,並且該函式中的引數分別為兩個回撥函式,用於進行不同的邏輯處理。

在定完一個promise物件之後,我們可以通過呼叫then方法來執行其對應的邏輯

pro.then(function(res){
    // 如果promise物件呼叫了resolve方法,則進入該函式邏輯
}, function(err){
    // 如果promise物件呼叫了reject方法,則進入該函式邏輯
})

promise的狀態

promise的例項主要有以下三種狀態:

①pending: 處理中

②fulfilled: 成功

③rejected: 失敗

pending狀態的promise可以轉化為fulfilled狀態或者rejected狀態,該轉化不可逆且只能轉化一次。同時,fulfilled狀態和rejected狀態只能由pending狀態轉化,相互不能轉化。如圖

img

pending狀態下的promise在處理完業務邏輯,且能正常退出時便可以執行resolve方法,從而進入fulfilled狀態;

若pending狀態下的promise在處理業務邏輯的過程中出現異常錯誤,或者主動呼叫reject方法,則進入rejected狀態。

let pro = new Promise(function(resolve, reject){
    if(// 邏輯處理完畢且能正常退出){
        resolve()
    }
    else{
        // 異常錯誤丟擲
        reject()
    }
})

pro.then(function(res){
    // 如果promise物件呼叫了resolve方法,則進入該函式邏輯
}, function(err){
    // 如果promise物件呼叫了reject方法,則進入該函式邏輯
})

鏈式呼叫

因為promise物件中的then方法的返回值是一個新的promise物件,因此可以實現鏈式呼叫。但後一個then方法的執行必須等待前一個then方法返回的promise物件狀態轉為fulfilled或者rejected,若promise物件處於pending狀態下,則後一個then方法只能等待。

pro.then(function(res){
    // 第一個promise物件邏輯執行
    return newPro;// 返回一個新promise
}).then(function(res){
    // 對newPro這個物件進行處理
})
// ...可以一直鏈式呼叫下去

異常捕捉

promise中的catch方法其實就是pro.then(null, rejection),使用者捕捉程式碼執行中的錯誤異常。

pro.then(function(res){
    // 邏輯處理,但存在異常
}).catch(function(err){
    // 捕捉上一個then函式中所出現的異常錯誤
})

此外,catch方法的所捕捉的異常不僅僅侷限於上一個then方法內,而是可以把錯誤一直傳遞下來,直至遇到的第一個catch,然後被捕捉。如鏈式呼叫中:

pro.then(function(res){
    // 邏輯處理,但存在異常
}).then({
    // 邏輯處理
}).catch(function(err){
    // 捕捉上面第一個出現異常的then函式中所出現的錯誤
})

promise.all

promise.all方法可以接受一個由promise組成的陣列作為引數,包裝成一個新的promise物件,並且按照陣列中promise的順序進行非同步執行。如:

let pro1 = new Promise(function(resolve, reject){})let pro2 = new Promise(function(resolve, reject){})let pro3 = new Promise(function(resolve, reject){})let proAll = promise.all([pro1, pro2, pro3]);

proAll的狀態由pro1,pro2,pro3三者共同決定:

①pending: 處理中,pro1,pro2,pro3中無rejected且存在pending狀態。

②rejected: pro1,pro2,pro3中存在一個rejected。

③fulfilled:pro1,pro2,pro3三者均為fulfilled。

當proAll的狀態為fulfilled時,會返回一個數組,該陣列中的元素則是上面由promise組成的陣列相對應執行後的結果。

promise.race

promise.race所接受的引數與promise.all一致,但promise.race的返回值則是由pro1,pro2,pro3三者中最先完成的promise物件決定,並且返回值為該最早完成的promise物件的返回值。

let proAll = promise.race([pro1, pro2, pro3]);

promise.resolve

promise.resolve方法能將一個物件轉換成promise物件

let newPro = promise.resolve(obj);

①若obj不具有then方法,則newPro直接變為fulfilled狀態

let newPro = promise.resolve('i am not a promise');

newPro.then(function(str){
    console.log(str) // 輸出 i am not a promise
})

②如果obj本就是一個Promise物件,則promise.resolve會將obj直接返回。

promise.reject

promise.reject方法與promise.resolve一樣,能將一個物件轉換成promise物件,但返回的promise物件的狀態為rejected。

async/await

async是關鍵詞,在一個函式名之前加上該關鍵詞,表明該函式內部有非同步操作,而這非同步操作應該返回一個promise物件,並且在這非同步操作之前新增await關鍵詞。當函式執行的時候,遇到await則會先進行Promise的邏輯處理,帶promise的狀態不再為pending時再執行該函式後面的語句。

let pro = new Promise(function(resolve, reject){
    // 非同步處理邏輯
    resolve();
})

async function asyncFunc(){
    // 正常執行的語句
    await pro;
    // 等待promise處理完之後再執行的語句
}

asyncFunc();

總結

promise的出現,為我們編寫非同步函式定下不少規則,在優化我們程式碼的同時也能減少程式碼量,並增強可讀性,但也需嚴格遵守promise/A+的規範進行promise的開發。

Facebook Profile photo
Written by Nat
This is the author box. A short description about the author of this article. Could be their website link, what they like to read about and so on. Profile