天天看點

JavaScript異步程式設計Promise

再次梳理一下同步和異步的差別:

同步:在執行一段代碼,沒有傳回結果之前,則不執行後面的代碼。會阻塞後面代碼的執行。

異步:與同步執行相反,在執行執行一段代碼沒有傳回結果時,通過一個回調函數來處理這個結果,繼續執行後面的代碼。

在ES6中,用Promise對象來表示異步的最終完成和結果。

Promise以下三個狀态:

待定(pending): 初始狀态。

已兌現(fulfilled): 意味着操作成功完成。

已拒絕(rejected): 意味着操作失敗。

pending狀态要麼轉化為fulfilled,要麼轉化為rejected狀态,通過promise的then方法和catch方法來傳回對應的promise對象。

const fs = require("fs")

let readFilePromise = (filename) => {
    return new Promise((resolve,) => {
        fs.readFile(filename, (err,) => {
            if (err) {
                reject(err)
            } else {
                resolve(data)
            }
        })
    })
}
readFilePromise('./fs.json').then(res => {
    console.log("res", res)
})      

每次任務執行結束後産生的失敗是直接被catch捕捉到的,因為Promise采用的是錯誤冒泡的方式,産生的錯誤會一直往後傳遞,直到被catch捕獲。這樣我們就不用頻繁的檢查錯誤了。

這就是Promise的好處:通過鍊式調用的方式來解決了多層嵌套的問題;Promise通過錯誤冒泡來統一做錯誤處理,這樣避免每個任務都要錯誤檢查導緻代碼混亂的問題。

Promise靜态方法

Promise.all

參數是可疊代的對象,比如數組,Promise.all是把多個異步操作并行執行,所有的異步都成功後才傳回成功,傳回的值也是按照入參的順序來傳回。如果有一個異步失敗,就傳回失敗,會把第一個異步失敗當成Promise.all的失敗結果傳回。

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

function getBannerList() {

    return new Promise((resolve,) => {

        setTimeout(function () {

            resolve('banner')

        }, 300)

    })

}

//2.擷取店鋪清單

function getStoreList() {

    return new Promise((resolve,) => {

        setTimeout(function () {

            resolve('store')

        }, 500)

    })

}

//3.擷取分類清單

function getCategoryList() {

    return new Promise((resolve,) => {

        setTimeout(function () {
            reject("失敗了")
            // resolve('category')

        }, 700)

    })

}

function initLoad() {

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

        .then(res => {

            console.log(res)

        }).catch(err => {

            console.log(err)

        })

}

initLoad()      

Promise.allSettled

和Promise.all相似,傳回一個對象數組,每個對象表示對應的異步任務的結果,不管異步任務的結果fulfilled還是reject。

Promise.allSettled适合多個彼此不依賴的異步任務,Promise.all更合适多個互相依賴的異步任務。

對之前的案例代碼稍微改造一下:

function initLoad() {

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

        .then(res => {

            console.log(res)

        }).catch(err => {

            console.log(err)

        })

}

initLoad();  // [{ status: 'fulfilled', value: 'banner' },{ status: 'fulfilled', value: 'store' },{ status: 'rejected', reason: '失敗了' }]      

Promise.any

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

傳回已經成功的異步任務,如果有多個異步都fulfilled了的,那就傳回第一個。如果所有的參數都變成rejected的話,那麼就傳回一個rejected。

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

function getBannerList() {

    return new Promise((resolve,) => {

        setTimeout(function () {

            reject('banner')

        }, 300)

    })

}

//2.擷取店鋪清單

function getStoreList() {

    return new Promise((resolve,) => {

        setTimeout(function () {

            reject('store')

        }, 500)

    })

}

//3.擷取分類清單

function getCategoryList() {

    return new Promise((resolve,) => {

        setTimeout(function () {
            reject("失敗了")
            // resolve('category')

        }, 700)

    })

}

function initLoad() {

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

        .then(res => {

            console.log(res)

        }).catch(err => {

            console.log(err)

        })

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

Promise.race

繼續閱讀