? ? ? ? 我們在上篇文章提到了異步會導致無法通過返回值來獲取函數的執行結果,我們通過傳入一個回調函數的方式,以參數的形式獲取到了我們想要獲取的數據,但是這樣如果需要對數據進行多次操作導致形成回調地獄那種不便于閱讀以及護理的代碼。
? ? ? ? 為了解決這個問題Promise(承諾)作為一個存儲數據的容器,幫助我們解決需要用回調函數的參數獲取異步函數執行結果的問題,擁有著一套特殊的存儲數據的方式。
1.Promise的介紹
? ? ? ? ? 首先就是創建Promise,我們要認識到Promise是一個構造函數,模擬類,通過new去實例化,Promise是內建的構造函數,本質上就是類,用new得到實例(承諾對象)
? ? ? ? Promise構造函數需要一個函數作為參數,Promise構造函數的回調函數會在創建Promiss時調用,同時會有兩個參數傳遞進去,resolve和reject兩個函數,通過這兩個函數可以向Promise存儲數據,resolve在執行正常的時候存儲數據 reject在執行錯誤的時候存儲數據。
? ? ? ? 當我們想要從Promise中讀取數據的時候,要通過Promise實例方法then去讀取Promise中存儲的數據,then需要兩個回調函數作為參數,resolve存儲的數據會在第一個函數中作為參數返回,reject存儲的數據或者丟出的錯誤會在第二個函數作為參數返回。
? ? ? ? 代碼如下。
????????
?????????
?????????
?????????
?
? ? ? ? Promise還隱藏了兩個隱藏屬性 PromiseReault存儲數據還有PromiseState記錄Promise的狀態(三種狀態 fulfilled(完成) rejected(出錯拒絕) pending(正在進行中)),state只能修改一次,修改以后永遠不會更改,state是私有的 reject和reslove只能運行一個。
? ? ? ? Promise的運行流程---
? ? ? ??當Promise創建的時候,PromiseState初始值是pending,當resolve存儲數據時,PromiseState變為fulfilled PromiseResult存儲數據。
????????當reject存儲數據時,PromiseState變為rejected?PromiseResult存儲數據或者異常對象。
? ? ? ? 當我們通過then讀取數據的時候,相當于為Promise設置了回調函數,如果PromiseState變為fulfilled則調用then第一個回調函數返回數據 如果是reject則調用第二個回調函數返回數據。
? ? ? ? catch和then類似,catch()相當于then(null,(reason)=>{})專門處理異常的方法
? ? ? ? finally()也是傳一個回調函數,無論正常存儲數據還是出現異常都會執行。一般用來編寫無論成功與否都需要執行的代碼邏輯。
????????
?2.Promise的詳情?
? ? ? ? 我們現在會使用Promise之后,搞一下原理.Promise就是一個存儲數據的對象,但是存儲方式特殊,所以可以直接將異步調用的結果存儲到Promise中。?
const Promise = new Promise((resolve,reject)=>{})
? ? ? ? 這句代碼中Promise里面的函數是我們傳進去的,resolve和reject是作為參數給我們返回的。所以我們定義這個函數就是為了讓Promise把resolbe和reject這兩個函數傳過來。然后resolve和reject存儲數據。
? ? ? ? 我們現在回歸正題,用promise去解決我們的回調地獄問題。
function sum(a,b,cb){setTimeout(()=>{cb(a+b)},1000)
}
const result=sum(1,1,(result)=>{sum(result,1,(result)=>{sum(result,1,(result)=>{sum(result,1,(result)=>{console.log(result);})})})
})
? ? ? 這是我們最開始沒有Promise的回調地獄。
? ? ? ?我們現在希望通過Promise去改進代碼。但是這時候我們發現我們好像欠缺了點東西。我們雖然存儲數據了但是我們想要實現多次調用還是需要一直調用
????????
? ? ? ? 這好像也是回調函數。
? ? ? ? 現在添加一個新知識點。Promise中的then和catch方法的返回值都會存儲到新的Promise中。這樣我們就知道如何去避免回調地獄了。
function sum1(a,b){return new Promise((resolve,reject)=>{setTimeout(()=>{resolve(a+b)},1000)})
}
const p1 =sum1(1,1).then((result)=>{return '楚河日當午'
})
const p3 = p1.then((result)=>{console.log(result);return 'gogogo'
})
p3.then((result)=>{console.log(result);
})
setTimeout(()=>{console.log('p1',p1)
},1000)//
? ? ? ? 我們可以第一個then返回一些數據然后賦值給一個變量,我們記得返回的是一個new Promise
然后PromiseResult就是我們的返回值,我們就可以再次通過then去獲取最新的值,就可以實現每次then都可以獲取到最新的值。
?????????
這樣就解決了我們的回調地獄這個問題,現在我們來看我們的catch方法。
?????????
? ? ? ? 我們發現在我們對Promise實例進行鏈式調用的時候,后面的方法thencatch讀取上一步的執行結果如果上一步的執行結果不是我們當前想要的,就會跳過當前的方法。
? ? ? ? 還有如果我們丟出錯誤沒有用catch捕獲就會報錯。(Promise調用鏈沒有catch卻扔出錯誤)
?????????
?
? ? ? ? Promise是甩鍋對象,如果catch出錯了會直接拋出錯誤,需要用catch捕獲。通常情況下catch寫最后面就不用這樣連續用了。相當于保安
????????
?????????
????????這里是一些擴展的方法以及使用方式。不常用。
? ? ? ? 這就是Promise的使用了,當然想要深度理解還需要去分清楚異步的執行順序宏任務和微任務,以及手寫Promise。如果僅僅是知道怎么去用,這就已經足夠了
?????????
?
????????
?????????