本篇文章通過(guò)多段代碼實(shí)例帶大家了解 Promise 的基礎(chǔ)用法,以及更進(jìn)一步掌握 Promise 異步存取的思想。
之前一直有聽(tīng)說(shuō) Promise 的威名,但是總覺(jué)得是個(gè)較為深?yuàn)W的東西,有點(diǎn)畏難而沒(méi)能真正地去了解。最近看了李立超老師在B站傳的 Node.js 的視頻,感覺(jué)講的很清晰,自己在這做進(jìn)一步的梳理。
(資料圖片)
我們都知道 JavaScript 是單線(xiàn)程運(yùn)行的,所以如果遇到一個(gè)數(shù)據(jù)需要過(guò)段時(shí)間才能獲取到的情況,就會(huì)形成阻塞導(dǎo)致后面的代碼也無(wú)法執(zhí)行,而這相當(dāng)致命,比如下面代碼
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 語(yǔ)句經(jīng)歷了10秒的循環(huán),最終才分別打印出了 3 和 1
然而我們希望的是允許3在10秒后再打印出來(lái),但是1得先打印出來(lái)
這里我們就用到了setTimeout,修改代碼如下
function sum(a, b) { setTimeout(() => { return a+b; },10000)}console.log(sum(1,2));console.log("1");運(yùn)行一下可以看到1確實(shí)瞬間被打印出來(lái)了,但是本該打印3的位置是undefined
原因在于此時(shí)的console.log同樣沒(méi)有等待setTimeout走完,無(wú)法接收到10秒后的數(shù)據(jù)
所以為了能夠接收到這個(gè)10秒后的數(shù)據(jù),我們可以采用回調(diào)函數(shù)的方式
function sum(a, b, callback) { setTimeout(() =>{ callback(a+b); }, 10000)}sum(1,2,(result) => { console.log(result);});console.log("1");傳入了一個(gè)能夠接收 a+b 為參數(shù)的回調(diào)函數(shù) (result) => {console.log(result);}
所以在10秒后會(huì)執(zhí)行這個(gè)回調(diào)函數(shù),進(jìn)行打印,結(jié)果如下
這樣我們就初步解決了這個(gè)問(wèn)題,一個(gè)需要延時(shí)獲取的數(shù)據(jù)在其他代碼先執(zhí)行后再被獲取。
然而 Promise 還沒(méi)出現(xiàn),這就涉及了另一個(gè)需要改進(jìn)的地方
這是個(gè)乍一聽(tīng)很唬人的稱(chēng)呼,實(shí)際上就是多層回調(diào)函數(shù)的嵌套導(dǎo)致的不利于閱讀和調(diào)試的情況。
比如此時(shí)我們想要多次調(diào)用這個(gè)sum函數(shù),要在得到1+2的結(jié)果后,再獲得 1+2+3,1+2+3+4 這些結(jié)果
所以我們得在sum傳入的回調(diào)函數(shù)里再多次調(diào)用sum進(jìn)行嵌套,如下
sum(1,2,(result) => { sum(result, 3, (result) => { sum(result, 4, (result) => { console.log(result); }) })});這種類(lèi)似金字塔的結(jié)構(gòu)可讀性差且不好調(diào)試,被稱(chēng)作回調(diào)地獄。
所以此時(shí)終于到了Promise出場(chǎng)的時(shí)候,它的出現(xiàn)解決了回調(diào)地獄的問(wèn)題。
在使用Promise解決回調(diào)地獄的問(wèn)題前,先來(lái)大致地了解一下什么是Promise。
目前我對(duì)它的判斷是,Promise 是一個(gè)用于存取異步數(shù)據(jù)的對(duì)象。
首先來(lái)看一下空的 Promise 打印出來(lái)會(huì)是什么
const promise = new Promise(()=>{});其中最關(guān)鍵的就是 PromiseState 和 PromiseResult 兩個(gè)值,之后會(huì)詳細(xì)展開(kāi),這里只要知道Promise中有著這兩個(gè)屬性即可。
接著來(lái)看一下 promise 存數(shù)據(jù)的過(guò)程,最關(guān)鍵的就是要知道有 resolve 和 reject,比如下面代碼
const promise = new Promise((resolve, reject) => { const flag = true; if (flag) { resolve("resolve datas"); } else { reject("reject data"); }})此時(shí)flag為true,所以執(zhí)行的是resolve的存儲(chǔ),得到的結(jié)果如下
而當(dāng)我們把flag改為false,執(zhí)行reject的存儲(chǔ)時(shí),得到的結(jié)果如下
現(xiàn)在是解釋上面兩個(gè)屬性的時(shí)候了,
當(dāng) promise 沒(méi)有存儲(chǔ)數(shù)據(jù)時(shí),PromiseState 的值為 pending,PromiseResult的值為 undefined當(dāng) promise 使用 resolve 存儲(chǔ)數(shù)據(jù)時(shí),PromiseState 的值為 pending,PromiseResult的值為 相應(yīng)存儲(chǔ)值當(dāng) promise 使用 reject 存儲(chǔ)數(shù)據(jù)時(shí),PromiseState 的值為 rejected,PromiseResult的值為相應(yīng)存儲(chǔ)值既然存有兩種類(lèi)型,讀自然也要分兩種
當(dāng)我們讀取promise中的數(shù)據(jù)時(shí),我們需要使用如下的結(jié)構(gòu)
promise.then(result => { console.log(result);}, reason => { console.log(reason);})如果數(shù)據(jù)存在resolve中,result會(huì)返回結(jié)果,如果存在reject中,reason會(huì)返回結(jié)果。
在初步了解了Promise后,會(huì)發(fā)現(xiàn)目前Promise能做的事,使用回調(diào)函數(shù)也能完成。
所以最主要的還是Promise解決了回調(diào)地獄,比如之前的問(wèn)題,可以寫(xiě)成這種形式
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 通過(guò)then方法進(jìn)行讀取后,是個(gè)新的Promise對(duì)象,比如我們可以打印一下
function sum(a, b) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(a+b); }, 1000); })}console.log(sum(1,2) .then(result => sum(result,3)))所以這也就給了我們能多次調(diào)用then方法的基礎(chǔ)。
而這也就解決了回調(diào)地獄的問(wèn)題。
Promise 是一個(gè)可以存取異步數(shù)據(jù)的對(duì)象,通過(guò)resolve和reject來(lái)存儲(chǔ)數(shù)據(jù),可以通過(guò)then來(lái)讀取數(shù)據(jù)
至于其他的.catch.finally.race.any.all這些方法就不再多作贅述,詳細(xì)的見(jiàn)文檔
【推薦學(xué)習(xí):javascript高級(jí)教程】
以上就是通過(guò)代碼實(shí)例帶你了解Promise的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注php中文網(wǎng)其它相關(guān)文章!
關(guān)鍵詞: JavaScript Node.js