首頁  >  文章  >  web前端  >  透過程式碼實例帶你了解Promise

透過程式碼實例帶你了解Promise

青灯夜游
青灯夜游轉載
2023-03-01 20:08:261778瀏覽

這篇文章透過多段程式碼實例帶大家了解 Promise 的基礎用法,以及更進一步掌握 Promise 非同步存取的想法。

透過程式碼實例帶你了解Promise

之前一直有聽說 Promise 的威名,但總覺得是個較為深奧的東西,有點畏難而沒能真正地去了解。最近看了李立超老師在B站傳的 Node.js 的視頻,感覺講的很清晰,自己在這做進一步的梳理。

先來看一個問題

我們都知道JavaScript 是單執行緒運行的,所以如果遇到一個資料需要過一段時間才能取得的情況,就會形成阻塞導致後面的程式碼也無法執行,而這相當致命,例如下面程式碼

function sum(a, b) {
    const begin = Date.now();
    while(Date.now() - begin < 10000) {

    }
    return a+b;
}

console.log(sum(1,2));
console.log("1");

中間的while 語句經歷了10秒的循環,最後才分別印出了3 和1

#然而我們希望的是允許3在10秒後再打印出來,但是1得先打印出來

這裡我們就用到了setTimeout,修改代碼如下

function sum(a, b) {
    setTimeout(() => {
        return a+b;
    },10000)
}

console.log(sum(1,2));
console.log("1");

運行一下可以看到1確實瞬間被打印出來了,但是本該打印3的位置是undefined

透過程式碼實例帶你了解Promise

#原因在於此時的console.log 同樣沒有等待setTimeout走完,無法接收10秒後的資料

所以為了能夠接收到這個10秒後的數據,我們可以採用回呼函數的方式

function sum(a, b, callback) {

    setTimeout(() =>{
        callback(a+b);
    }, 10000)

}

sum(1,2,(result) => {
    console.log(result);
});
console.log("1");

傳入了一個能夠接收a b 為參數的回呼函數(result) => {console.log(result);}

##所以在10秒後會執行這個回呼函數,進行列印,結果如下

透過程式碼實例帶你了解Promise

這樣我們就初步解決了這個問題,一個需要延時取得的資料在其他程式碼先執行後再被獲取。

然而Promise 還沒出現,這就涉及了另一個需要改進的地方

#回調地獄

這是個乍聽很唬人的稱呼,其實就是多層回調函數的嵌套所導致的不利於閱讀和調試的情況。

例如此時我們想要多次呼叫這個sum函數,要在得到1 2的結果後,再得到1 2 3,1 2 3 4 這些結果

所以我們得在sum傳入的回呼函數裡再多次呼叫sum進行嵌套,如下

sum(1,2,(result) => {
    sum(result, 3, (result) => {
        sum(result, 4, (result) => {
            console.log(result);
        })
    })
});

透過程式碼實例帶你了解Promise

#這種類似金字塔的結構可讀性差且不好調試,被稱為回調地獄。

所以此時終於到了Promise出場的時候,它的出現解決了回調地獄的問題。

Promise 是什麼

在使用Promise解決回呼地獄的問題前,先來大致了解一下什麼是Promise。

目前我對它的判斷是,Promise 是用來存取非同步資料的物件。

先來看看空的Promise 印出來會是什麼

const promise = new Promise(()=>{});

透過程式碼實例帶你了解Promise

其中最關鍵的就是PromiseState 和PromiseResult 兩個值,之後會詳細展開,這裡只要知道Promise中有著這兩個屬性即可。

接著來看一下promise 存資料的過程,最關鍵的就是要知道有resolve 和reject,例如下面程式碼

const promise = new Promise((resolve, reject) => {
    const flag = true;
    if (flag) {
        resolve("resolve datas");
    } else {
        reject("reject data");
    }
})

此時flag為true,所以執行的是resolve的存儲,得到的結果如下

透過程式碼實例帶你了解Promise

而當我們把flag改為false,執行reject的儲存時,得到的結果如下

透過程式碼實例帶你了解Promise

現在是解釋上面兩個屬性的時候了,

    當promise 沒有儲存資料時,PromiseState 的值為pending,PromiseResult的值為undefined
  • 當promise使用resolve 儲存資料時,PromiseState 的值為pending,PromiseResult的值為對應儲存值
  • 當promise 使用reject 儲存資料時,PromiseState 的值為rejected,PromiseResult的值為對應儲存值
既然存有兩種類型,讀自然也要分兩種

當我們讀取promise中的數據時,我們需要使用如下的結構

promise.then(result => {
    console.log(result);
}, reason => {
    console.log(reason);
})

如果數據存在resolve中,result會回傳結果,如果存在reject中,reason會回傳結果。

使用Promise解決回呼地獄

初步了解了Promise後,會發現目前Promise能做的事,使用回呼函數也能完成。

所以最主要的還是Promise解決了回調地獄,例如之前的問題,可以寫成這種形式

function sum(a, b) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(a+b);
        }, 1000);
    })
}

sum(1,2)
    .then(result => sum(result,3))
    .then(result => sum(result,4))
    .then(result => {
        console.log(result);
    })

promise 通过then方法进行读取后,是个新的Promise对象,比如我们可以打印一下

function sum(a, b) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(a+b);
        }, 1000);
    })
}

console.log(sum(1,2)
    .then(result => sum(result,3)))

透過程式碼實例帶你了解Promise

所以这也就给了我们能多次调用then方法的基础。

而这也就解决了回调地狱的问题。

小结

Promise 是一个可以存取异步数据的对象,通过resolvereject来存储数据,可以通过then来读取数据

至于其他的.catch .finally .race .any .all 这些方法就不再多作赘述,详细的见文档

【推荐学习:javascript高级教程

以上是透過程式碼實例帶你了解Promise的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.cn。如有侵權,請聯絡admin@php.cn刪除