天天看點

JavaScript:Promise進階知識

Promise

Promise就是ES6新增的一個用于解決異步程式設計的方案。以前,我們在處理異步的時候,都是在回調函數内做處理的。比如Ajax請求,是在success屬性裡面做異步處理的,那麼如果在一個請求中需要執行讀個異步請求,第二個請求是依賴于第一個請求的結果,這樣就導緻代碼嵌套很深,可讀性差、很難維護并且難以複用。

那麼Promise正好可以解決這樣的問題,Promise有3種狀态:pending、fulfilled和rejected。Promise在建立階段是屬于pending狀态,接着狀态隻能有兩種一個數fulfilled或者rejected,狀态改變後就不能再發生變化了,例如:

const promise = new Promise((resolve, rejected) => {
    // 異步請求處理
    if (/異步請求/) {
        resolve();
    } else {
        rejected();
    }
})      

異步請求成功,則執行resolve函數,否則執行rejected函數,resolve和rejected函數可以傳參數,作為後面.then函數或者catch函數的資料源。

Promise在建立後立即調用,然後等待執行resolve或者是rejected函數來确定Promise的最終狀态,比如下面代碼:

const promise = new Promise((resolve, rejected) => {
    console.log("Promise");
    resolve();
})

promise.then(() => {
    console.log("resolve")
});

console.log("hello")      

結果就是Promise,hello,resolve。因為Promise建立後會立即執行,輸出Promise;然後是執行resolve函數,這樣就會觸發then函數裡面的回調函數,但是它需要等待目前線程代碼執行完畢後再執行,縮回跳過,先執行後面的代碼,輸出hello,最後執行then的回調函數,輸出resolve。

then函數,傳回的是一個Promise對象執行個體,是以可以通過鍊式調用then函數,在上一個then函數内return的值是下一個then函數接收的資料,比如:

const promise = new Promise((resolve, rejected) => {
    resolve(1);
})

promise.then((res) => {
    console.log(res);
    return 2;
}).then(res => {
    console.log(res);
    return 3;
}).then(res => {
    console.log(res)
})      

結果就是一次列印1,2,3。這樣就是可以解決異步回調地獄的問題。

catch函數,是Promise執行失敗的回調。如果我們在Promise中手動抛出一個異常,來測試catch函數,代碼如下:

const promise1 = new Promise((resolve, rejected) => {
    try {
        throw new Error("測試");
    } catch (error) {
        rejected(error)
    }
})

promise1.catch(err=>{
    console.log(err); // Error: 測試
})      

然而Promise在執行中,如果出現異常就會自動抛出,這樣上面的代碼可以改為:

const promise1 = new Promise((resolve, rejected) => {
    throw new Error("測試");
})

promise1.catch(err=>{
    console.log(err); // Error: 測試
})      

但是需要注意,Promise的狀态一旦變味fulfilled成功狀态,然後再抛出異常,是不能觸發catch的,因為前面已經說過了Promise的狀态隻要發生變化後就不能再次更改。

Promise靜态方法

Promise.all()函數

将多個Promise對象執行個體包裝成為一個Promise執行個體,參數是一個數組,這個Promise的狀态是由所有傳入Promise對象來決定,當所有的Promise的狀态為fulfilled,這個新的Promise的狀态才是fulfilled狀态,如果有一個promise的狀态為rejected,那麼這個新Promise的狀态就是reject。

現在使用一段代碼來了解上面的描述:

const p1 = new Promise((resolve, reject) => {
    resolve("success")
})

const p2 = new Promise((resolve, reject) => {
    resolve(1)
})

const p = Promise.all([p1, p2]);
p.then(res => {
    console.log(res);
}).catch(err => {
    console.log(err)
})
// [ 'success', 1 ]      

如果p1,p2中已經定義了對應的catch,當有一個promise狀态變為reject的話,promise.all不會觸發catch函數了,比如:

const p1 = new Promise((resolve, reject) => {
    resolve("success")
}).then(res => res).catch(err => err)

const p2 = new Promise((resolve, reject) => {
    throw new Error("報錯")
}).then(res => res).catch(err => err)

const p = Promise.all([p1, p2]);
p.then(res => {
    console.log(res)
}).catch(err => {
    console.log(err)
})
// [ 'success',  Error: 報錯 ]      
Promise.race 函數

通過race方法來合并多個promise,那麼這個promise狀态是最先更新狀态的promise的狀态,比如:

const p1 = new Promise((resolve, reject) => {
}).then(res => res).catch(err => err)

const p2 = new Promise((resolve, reject) => {
    reject("失敗了")
}).then(res => res).catch(err => err)
const race = Promise.race([p1, p2]);
race.then(res => {
    console.log(res)
}).catch(err => {
    console.log(err)
}) // 失敗了      
Promise.any函數

傳入一個可疊代的參數,如數組。

結果為:

1、所有promise狀态都為成功,傳回的是第一個promise的成功狀态

//1.擷取輪播資料清單

function getBannerList() {
    return new Promise((resolve, reject) => {
        resolve('banner')
    })
}

//2.擷取店鋪清單

function getStoreList() {
    return new Promise((resolve, reject) => {
        resolve('store')
    })
}

//3.擷取分類清單

function getCategoryList() {
    return new Promise((resolve, reject) => {
        resolve("失敗了")
    })
}

function initLoad() {

    Promise.any([getBannerList(), getStoreList(), getCategoryList()])

        .then(res => {

            console.log(res)

        }).catch(err => {

            console.log(err)

        })

}
initLoad(); // banner      
//1.擷取輪播資料清單

function getBannerList() {
    return new Promise((resolve, reject) => {
        reject('banner')
    })
}

//2.擷取店鋪清單

function getStoreList() {
    return new Promise((resolve, reject) => {
        resolve('store')
    })
}

//3.擷取分類清單

function getCategoryList() {
    return new Promise((resolve, reject) => {
        resolve("失敗了")
    })
}

function initLoad() {

    Promise.any([getBannerList(), getStoreList(), getCategoryList()])

        .then(res => {

            console.log(res)

        }).catch(err => {

            console.log(err)

        })

}
initLoad(); // store      
//1.擷取輪播資料清單

function getBannerList() {
    return new Promise((resolve, reject) => {
        reject('banner')
    })
}

//2.擷取店鋪清單

function getStoreList() {
    return new Promise((resolve, reject) => {
        reject('store')
    })
}

//3.擷取分類清單

function getCategoryList() {
    return new Promise((resolve, reject) => {
        reject("失敗了")
    })
}

function initLoad() {

    Promise.any([getBannerList(), getStoreList(), getCategoryList()])

        .then(res => {

            console.log(res)

        }).catch(err => {

            console.log(err)

        })

}
initLoad(); // [AggregateError: All promises were rejected]      

繼續閱讀