本篇文章通過多段程式碼範例帶大家瞭解 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
原因在於此時的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 還沒出現,這就涉及了另一個需要改進的地方
這是個乍一聽很唬人的稱呼,實際上就是多層回撥函數的巢狀導致的不利於閱讀和偵錯的情況。
比如此時我們想要多次呼叫這個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 列印出來會是什麼
const promise = new 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的儲存,得到的結果如下
而當我們把flag改為false,執行reject的儲存時,得到的結果如下
現在是解釋上面兩個屬性的時候了,
既然存有兩種型別,讀自然也要分兩種
當我們讀取promise中的資料時,我們需要使用如下的結構
promise.then(result => {
console.log(result);
}, reason => {
console.log(reason);
})
登入後複製
如果資料存在resolve中,result會返回結果,如果存在reject中,reason會返回結果。
在初步瞭解了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)))
登入後複製
所以這也就給了我們能多次呼叫then方法的基礎。
而這也就解決了回撥地獄的問題。
Promise 是一個可以存取非同步資料的物件,通過resolve
和reject
來儲存資料,可以通過then
來讀取資料
至於其他的.catch
.finally
.race
.any
.all
這些方法就不再多作贅述,詳細的見檔案
【推薦學習:】
以上就是通過程式碼範例帶你瞭解Promise的詳細內容,更多請關注TW511.COM其它相關文章!