promise

promise是什么?

1、主要用于異步計(jì)算

2、可以將異步操作隊(duì)列化,按照期望的順序執(zhí)行,返回符合預(yù)期的結(jié)果

3、可以在對(duì)象之間傳遞和操作promise,幫助我們處理隊(duì)列

為什么會(huì)有promise?

為了避免界面凍結(jié)(任務(wù))

同步:假設(shè)你去了一家飯店,找個(gè)位置,叫來(lái)服務(wù)員,這個(gè)時(shí)候服務(wù)員對(duì)你說(shuō),對(duì)不起我是“同步”服務(wù)員,我要服務(wù)完這張桌子才能招呼你。那桌客人明明已經(jīng)吃上了,你只是想要個(gè)菜單,這么小的動(dòng)作,服務(wù)員卻要你等到別人的一個(gè)大動(dòng)作完成之后,才能再來(lái)招呼你,這個(gè)便是同步的問(wèn)題:也就是“順序交付的工作1234,必須按照1234的順序完成”。

異步:則是將耗時(shí)很長(zhǎng)的A交付的工作交給系統(tǒng)之后,就去繼續(xù)做B交付的工作,。等到系統(tǒng)完成了前面的工作之后,再通過(guò)回調(diào)或者事件,繼續(xù)做A剩下的工作。

AB工作的完成順序,和交付他們的時(shí)間順序無(wú)關(guān),所以叫“異步”。

異步操作的常見(jiàn)語(yǔ)法

事件監(jiān)聽(tīng)

document.getElementById('#start').addEventListener('click',start,false);functionstart(){// 響應(yīng)事件,進(jìn)行相應(yīng)的操作}// jquery on 監(jiān)聽(tīng)$('#start').on('click',start)

回調(diào)

// 比較常見(jiàn)的有ajax$.ajax('http://www.wyunfei.com/',{success(res){// 這里可以監(jiān)聽(tīng)res返回的數(shù)據(jù)做回調(diào)邏輯的處理}})// 或者在頁(yè)面加載完畢后回調(diào)$(function(){// 頁(yè)面結(jié)構(gòu)加載完成,做回調(diào)邏輯處理})

有了nodeJS之后...對(duì)異步的依賴進(jìn)一步加劇了

大家都知道在nodeJS出來(lái)之前PHP、Java、python等后臺(tái)語(yǔ)言已經(jīng)很成熟了,nodejs要想能夠有自己的一片天,那就得拿出點(diǎn)自己的絕活:

無(wú)阻塞高并發(fā),是nodeJS的招牌,要達(dá)到無(wú)阻塞高并發(fā)異步是其基本保障

舉例:查詢數(shù)據(jù)從數(shù)據(jù)庫(kù),PHP第一個(gè)任務(wù)查詢數(shù)據(jù),后面有了新任務(wù),那么后面任務(wù)會(huì)被掛起排隊(duì);而nodeJS是第一個(gè)任務(wù)掛起交給數(shù)據(jù)庫(kù)去跑,然后去接待第二個(gè)任務(wù)交給對(duì)應(yīng)的系統(tǒng)組件去處理掛起,接著去接待第三個(gè)任務(wù)...那這樣子的處理必然要依賴于異步操作

異步回調(diào)的問(wèn)題:

之前處理異步是通過(guò)純粹的回調(diào)函數(shù)的形式進(jìn)行處理

很容易進(jìn)入到回調(diào)地獄中,剝奪了函數(shù)return的能力

問(wèn)題可以解決,但是難以讀懂,維護(hù)困難

稍有不慎就會(huì)踏入回調(diào)地獄 - 嵌套層次深,不好維護(hù)

回調(diào)地獄

一般情況我們一次性調(diào)用API就可以完成請(qǐng)求。

有些情況需要多次調(diào)用服務(wù)器API,就會(huì)形成一個(gè)鏈?zhǔn)秸{(diào)用,比如為了完成一個(gè)功能,我們需要調(diào)用API1、API2、API3,依次按照順序進(jìn)行調(diào)用,這個(gè)時(shí)候就會(huì)出現(xiàn)回調(diào)地獄的問(wèn)題

promise

promise是一個(gè)對(duì)象,對(duì)象和函數(shù)的區(qū)別就是對(duì)象可以保存狀態(tài),函數(shù)不可以(閉包除外)

并未剝奪函數(shù)return的能力,因此無(wú)需層層傳遞callback,進(jìn)行回調(diào)獲取數(shù)據(jù)

代碼風(fēng)格,容易理解,便于維護(hù)

多個(gè)異步等待合并便于解決

promise詳解

newPromise(function(resolve,reject){// 一段耗時(shí)的異步操作resolve('成功')// 數(shù)據(jù)處理完成// reject('失敗') // 數(shù)據(jù)處理出錯(cuò)}).then((res)=>{console.log(res)},// 成功(err)=>{console.log(err)}// 失敗)

resolve作用是,將Promise對(duì)象的狀態(tài)從“未完成”變?yōu)椤俺晒Α保磸?pending 變?yōu)?resolved),在異步操作成功時(shí)調(diào)用,并將異步操作的結(jié)果,作為參數(shù)傳遞出去;

reject作用是,將Promise對(duì)象的狀態(tài)從“未完成”變?yōu)椤笆 保磸?pending 變?yōu)?rejected),在異步操作失敗時(shí)調(diào)用,并將異步操作報(bào)出的錯(cuò)誤,作為參數(shù)傳遞出去。

promise有三個(gè)狀態(tài):

1、pending[待定]初始狀態(tài)

2、fulfilled[實(shí)現(xiàn)]操作成功

3、rejected[被否決]操作失敗

當(dāng)promise狀態(tài)發(fā)生改變,就會(huì)觸發(fā)then()里的響應(yīng)函數(shù)處理后續(xù)步驟;

promise狀態(tài)一經(jīng)改變,不會(huì)再變。

Promise對(duì)象的狀態(tài)改變,只有兩種可能:

從pending變?yōu)閒ulfilled

從pending變?yōu)閞ejected。

這兩種情況只要發(fā)生,狀態(tài)就凝固了,不會(huì)再變了。

最簡(jiǎn)單示例:

newPromise(resolve=>{setTimeout(()=>{resolve('hello')},2000)}).then(res=>{console.log(res)})

分兩次,順序執(zhí)行

newPromise(resolve=>{setTimeout(()=>{resolve('hello')},2000)}).then(val=>{console.log(val)//? 參數(shù)val = 'hello'returnnewPromise(resolve=>{setTimeout(()=>{resolve('world')},2000)})}).then(val=>{console.log(val)// 參數(shù)val = 'world'})

promise完成后then()

letpro=newPromise(resolve=>{setTimeout(()=>{resolve('hello world')},2000)})setTimeout(()=>{pro.then(value=>{console.log(value)// hello world})},2000)

結(jié)論:promise作為隊(duì)列最為重要的特性,我們?cè)谌魏我粋€(gè)地方生成了一個(gè)promise隊(duì)列之后,我們可以把他作為一個(gè)變量傳遞到其他地方。

假如在.then()的函數(shù)里面不返回新的promise,會(huì)怎樣?

.then()

1、接收兩個(gè)函數(shù)作為參數(shù),分別代表fulfilled(成功)和rejected(失敗)

2、.then()返回一個(gè)新的Promise實(shí)例,所以它可以鏈?zhǔn)秸{(diào)用

3、當(dāng)前面的Promise狀態(tài)改變時(shí),.then()根據(jù)其最終狀態(tài),選擇特定的狀態(tài)響應(yīng)函數(shù)執(zhí)行

4、狀態(tài)響應(yīng)函數(shù)可以返回新的promise,或其他值,不返回值也可以我們可以認(rèn)為它返回了一個(gè)null;

5、如果返回新的promise,那么下一級(jí).then()會(huì)在新的promise狀態(tài)改變之后執(zhí)行

6、如果返回其他任何值,則會(huì)立即執(zhí)行下一級(jí).then()

.then()里面有.then()的情況

1、因?yàn)?then()返回的還是Promise實(shí)例

2、會(huì)等里面的then()執(zhí)行完,再執(zhí)行外面的

then嵌套

對(duì)于我們來(lái)說(shuō),此時(shí)最好將其展開(kāi),也是一樣的結(jié)果,而且會(huì)更好讀:

展開(kāi)增加可讀性

錯(cuò)誤處理

Promise會(huì)自動(dòng)捕獲內(nèi)部異常,并交給rejected響應(yīng)函數(shù)處理。

第一種錯(cuò)誤處理

第一種錯(cuò)誤處理

第二種錯(cuò)誤處理

第二種錯(cuò)誤處理

錯(cuò)誤處理兩種做法:

第一種:reject('錯(cuò)誤信息').then(() => {}, () => {錯(cuò)誤處理邏輯})

第二種:throw new Error('錯(cuò)誤信息').catch( () => {錯(cuò)誤處理邏輯})

推薦使用第二種方式,更加清晰好讀,并且可以捕獲前面所有的錯(cuò)誤(可以捕獲N個(gè)then回調(diào)錯(cuò)誤)

catch() + then()

第一種情況:

第一種情況

第一種情況 - 結(jié)果

結(jié)論:catch也會(huì)返回一個(gè)promise實(shí)例,并且是resolved狀態(tài)

第二種情況:

第二種情況

第二種情況結(jié)果

結(jié)論:拋出錯(cuò)誤變?yōu)閞ejected狀態(tài),所以繞過(guò)兩個(gè)then直接跑到最下面的catch

Promise.all() 批量執(zhí)行

Promise.all([p1, p2, p3])用于將多個(gè)promise實(shí)例,包裝成一個(gè)新的Promise實(shí)例,返回的實(shí)例就是普通的promise

它接收一個(gè)數(shù)組作為參數(shù)

數(shù)組里可以是Promise對(duì)象,也可以是別的值,只有Promise會(huì)等待狀態(tài)改變

當(dāng)所有的子Promise都完成,該P(yáng)romise完成,返回值是全部值得數(shù)組

有任何一個(gè)失敗,該P(yáng)romise失敗,返回值是第一個(gè)失敗的子Promise結(jié)果

//切菜functioncutUp(){console.log('開(kāi)始切菜。');varp=newPromise(function(resolve,reject){//做一些異步操作setTimeout(function(){console.log('切菜完畢!');resolve('切好的菜');},1000);});returnp;}//燒水functionboil(){console.log('開(kāi)始燒水。');varp=newPromise(function(resolve,reject){//做一些異步操作setTimeout(function(){console.log('燒水完畢!');resolve('燒好的水');},1000);});returnp;}Promise.all([cutUp(),boil()]).then((result)=>{console.log('準(zhǔn)備工作完畢');console.log(result);})

Promise.race() 類似于Promise.all() ,區(qū)別在于它有任意一個(gè)完成就算完成

letp1=newPromise(resolve=>{setTimeout(()=>{resolve('I\`m p1 ')},1000)});letp2=newPromise(resolve=>{setTimeout(()=>{resolve('I\`m p2 ')},2000)});Promise.race([p1,p2]).then(value=>{console.log(value)})

常見(jiàn)用法:

異步操作和定時(shí)器放在一起,,如果定時(shí)器先觸發(fā),就認(rèn)為超時(shí),告知用戶;

例如我們要從遠(yuǎn)程的服務(wù)家在資源如果5000ms還沒(méi)有加載過(guò)來(lái)我們就告知用戶加載失敗

現(xiàn)實(shí)中的用法

回調(diào)包裝成Promise,他有兩個(gè)顯而易見(jiàn)的好處:

1、可讀性好

2、返回 的結(jié)果可以加入任何Promise隊(duì)列

實(shí)戰(zhàn)示例,回調(diào)地獄和promise對(duì)比:

/***

? 第一步:找到北京的id

? 第二步:根據(jù)北京的id -> 找到北京公司的id

? 第三步:根據(jù)北京公司的id -> 找到北京公司的詳情

? 目的:模擬鏈?zhǔn)秸{(diào)用、回調(diào)地獄

***/// 回調(diào)地獄// 請(qǐng)求第一個(gè)API: 地址在北京的公司的id$.ajax({url:'https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/city',success(resCity){letfindCityId=resCity.filter(item=>{if(item.id=='c1'){returnitem}})[0].id? ? ? ? ? $.ajax({//? 請(qǐng)求第二個(gè)API: 根據(jù)上一個(gè)返回的在北京公司的id “findCityId”,找到北京公司的第一家公司的idurl:'https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/position-list',success(resPosition){letfindPostionId=resPosition.filter(item=>{if(item.cityId==findCityId){returnitem}})[0].id// 請(qǐng)求第三個(gè)API: 根據(jù)上一個(gè)API的id(findPostionId)找到具體公司,然后返回公司詳情$.ajax({url:'https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/company',success(resCom){letcomInfo=resCom.filter(item=>{if(findPostionId==item.id){returnitem}})[0]console.log(comInfo)}})}})}})

// Promise 寫(xiě)法// 第一步:獲取城市列表constcityList=newPromise((resolve,reject)=>{$.ajax({url:'https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/city',success(res){resolve(res)}})})// 第二步:找到城市是北京的idcityList.then(res=>{letfindCityId=res.filter(item=>{if(item.id=='c1'){returnitem}})[0].idfindCompanyId().then(res=>{// 第三步(2):根據(jù)北京的id -> 找到北京公司的idletfindPostionId=res.filter(item=>{if(item.cityId==findCityId){returnitem}})[0].id// 第四步(2):傳入公司的idcompanyInfo(findPostionId)})})// 第三步(1):根據(jù)北京的id -> 找到北京公司的idfunctionfindCompanyId(){letaaa=newPromise((resolve,reject)=>{$.ajax({url:'https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/position-list',success(res){resolve(res)}})})returnaaa}// 第四步:根據(jù)上一個(gè)API的id(findPostionId)找到具體公司,然后返回公司詳情functioncompanyInfo(id){letcompanyList=newPromise((resolve,reject)=>{$.ajax({url:'https://www.easy-mock.com/mock/5a52256ad408383e0e3868d7/lagou/company',success(res){letcomInfo=res.filter(item=>{if(id==item.id){returnitem}})[0]console.log(comInfo)}})})}


作者:王云飛_小四_wyunfei

鏈接:http://www.itdecent.cn/p/1b63a13c2701

來(lái)源:簡(jiǎn)書(shū)

著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • promise是什么? 1、主要用于異步計(jì)算 2、可以將異步操作隊(duì)列化,按照期望的順序執(zhí)行,返回符合預(yù)期的結(jié)果 3...
    Koreyoshi丶閱讀 251評(píng)論 0 1
  • 首先說(shuō)一下promise 是什么? 1、本質(zhì)是構(gòu)造函數(shù)中主要用于異步計(jì)算 2、可以將異步操作隊(duì)列化,按照期望的順序...
    只是墨辰閱讀 2,592評(píng)論 0 0
  • promise是什么? 1、主要用于異步計(jì)算 2、可以將異步操作隊(duì)列化,按照期望的順序執(zhí)行,返回符合預(yù)期的結(jié)果 3...
    師妹不叫思妹閱讀 877評(píng)論 0 0
  • Promise是什么? 1、主要用于異步計(jì)算 2、可以將異步操作隊(duì)列化,按照期望的順序執(zhí)行,返回符合預(yù)期的結(jié)果 3...
    uptome_b2ef閱讀 244評(píng)論 0 0
  • Promise 對(duì)象 Promise 的含義 Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函...
    neromous閱讀 8,836評(píng)論 1 56

友情鏈接更多精彩內(nèi)容