摘要:第一個(gè)回調(diào)函數(shù)完成后,會(huì)將返回結(jié)果作為參數(shù),傳入第二個(gè)回調(diào)函數(shù)。采用鏈?zhǔn)降模梢灾付ㄒ唤M按照次序調(diào)用的回調(diào)函數(shù)。這時(shí),第二個(gè)方法指定的回調(diào)函數(shù),就會(huì)等待這個(gè)新的對(duì)象狀態(tài)發(fā)生變化。處理和前一個(gè)回調(diào)函數(shù)運(yùn)行時(shí)發(fā)生的錯(cuò)誤。
1.Promise的含義
Promise是異步編程的一種解決方案,比傳統(tǒng)的解決方案--回調(diào)函數(shù)和事件更合理更強(qiáng)大。所謂Promise,簡(jiǎn)單說(shuō)就是一個(gè)容器,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果。
Promise對(duì)象有以下兩個(gè)特點(diǎn):
(1)對(duì)象的狀態(tài)不受外界影響。Promise對(duì)象代表一個(gè)異步操作,有三種狀態(tài):pending(進(jìn)行中)、fulfiled(已成功)和rejected(已失敗)。只有異步操作的結(jié)果,可以決定當(dāng)前是哪一種狀態(tài),任何其它操作都無(wú)法改變這個(gè)狀態(tài)。
(2)一旦狀態(tài)改變,就不會(huì)再變,任何時(shí)候都可以得到這個(gè)結(jié)果。Promise對(duì)象的狀態(tài)改變,只有兩種可能:從pending變?yōu)閒ulfiled和從pending變?yōu)閞ejected。只要這兩種情況發(fā)生,狀態(tài)就凝固了,不會(huì)再變了,會(huì)一直保持這個(gè)結(jié)果,這時(shí)就稱為resolved(已定型)。
缺點(diǎn):
首先,無(wú)法取消Promise,一旦新建他就會(huì)立即執(zhí)行,無(wú)法中途取消。其次,如果不設(shè)置回調(diào)函數(shù),Promise內(nèi)部拋出的錯(cuò)誤,不會(huì)反應(yīng)到外部。第三,當(dāng)處與pending狀態(tài)時(shí),無(wú)法得知目前進(jìn)展到哪一個(gè)階段。
下面的代碼創(chuàng)造了一個(gè)Promise實(shí)例。
const promise = new Promise(function(resolve,reject){ if(/*異步操作成功*/){ resolve(value); }else{ reject(error); } });
Promise構(gòu)造函數(shù)接受一個(gè)函數(shù)作為參數(shù),該函數(shù)的兩個(gè)參數(shù)分別是resolve和reject。它們是兩個(gè)函數(shù),由JavaScript引擎提供,不用自己部署。
resolve函數(shù)的作用是,將Promise對(duì)象的狀態(tài)從未完成變?yōu)槌晒Γ诋惒讲僮鲿r(shí)調(diào)用,并將異步操作的結(jié)果,作為參數(shù)傳遞出去;reject函數(shù)的作用是,將Promise對(duì)象的狀態(tài)從未完成變?yōu)槭。诋惒讲僮魇r(shí)調(diào)用,并將異步操作報(bào)出的錯(cuò)誤,作為參數(shù)傳遞出去。
Promise實(shí)例生成以后,可以用then方法分別指定resolved狀態(tài)和rejected狀態(tài)的回調(diào)函數(shù)。
promise.then(function(value){ //success },function(error){ //failure })
then方法可以接受兩個(gè)回調(diào)函數(shù)作為參數(shù)。第一個(gè)回調(diào)函數(shù)是Promsie對(duì)象的狀態(tài)變?yōu)閞esolved時(shí)調(diào)用,第二個(gè)回調(diào)函數(shù)是Promise對(duì)象的狀態(tài)變?yōu)閞ejected時(shí)調(diào)用。其中,第二個(gè)函數(shù)是可選的,不一定要提供。這兩個(gè)函數(shù)都接受Promise對(duì)象傳出的值作為參數(shù)。
下面是一個(gè)Promise對(duì)象的簡(jiǎn)單例子:
function timeout(ms){ return new Promise((resolve,reject)=>{ setTimeout(resolve,ms,"done"); }) } timeout(100).then((value)=>{ console.log(value); })
上面代碼中,timeout方法返回一個(gè)Promise實(shí)例,表示一段時(shí)間后才會(huì)發(fā)生的結(jié)果。過(guò)了指定時(shí)間以后,promise實(shí)力的狀態(tài)變?yōu)閞esolved,就會(huì)觸發(fā)then方法綁定的回調(diào)函數(shù)。
Promise新建后就會(huì)立即執(zhí)行。下面代碼中,Promise新建后立即執(zhí)行,所以首先輸出的是Promise。然后,then方法指定的回調(diào)函數(shù),將在當(dāng)前腳本所有同步任務(wù)執(zhí)行完才會(huì)執(zhí)行,所以resolved最后輸出。
let promise = new Promise(function(resolve,reject){ console.log("Promise"); resolve(1) }); promise.then(function(value){ console.log("resolved"); console.log(value) }); console.log("Hi"); //Promise //Hi! //resolved //1
如果調(diào)用resolve函數(shù)和reject函數(shù)時(shí)帶有參數(shù),那么它們的參數(shù)會(huì)被傳遞給回調(diào)函數(shù)。reject函數(shù)的參數(shù)通常是Error對(duì)象的實(shí)例,表示拋出錯(cuò)誤;resolve函數(shù)的參數(shù)除了正常的值以外,還可能是另一個(gè)Promise實(shí)例。比如像下面這樣。p1和p2都是Promise實(shí)例,但是p2的resolve方法將p1作為參數(shù),即一個(gè)異步操作的結(jié)果返回另一個(gè)異步操作。
const p1 = new Promise(function(resolve,reject){ //... }); const p2 = new Promise(function(resolve,reject){ //.... resolve(p1); })
注意:這時(shí)p1的狀態(tài)就會(huì)傳遞給p2,也就是說(shuō),p1的狀態(tài)決定了p2的狀態(tài)。如果p1的狀態(tài)是pending,那么p2的回調(diào)函數(shù)就會(huì)等待p1的狀態(tài)改變;如果p1的狀態(tài)已經(jīng)是resolved或則rejected,那么p2的回調(diào)函數(shù)將會(huì)立刻執(zhí)行。
const p1 = new Promise(function(resolve,reject){ setTimeout(()=>reject(new Error("fail")),3000); }); const p2 = new Promise(function(resolve,reject){ setTimeout(()=>resolve(p1),1000) }); p2.then(result=>console.log(result)) .catch(error=>console.log(error));//Error:fail
上面代碼中,p1是一個(gè)Promise,3秒之后變?yōu)閞ejected。p2的狀態(tài)在1秒之后改變,resolve方法返回的是p1.由于p2返回的是另一個(gè)Promise,導(dǎo)致p2自己的狀態(tài)無(wú)效了,由p1的狀態(tài)決定p2的狀態(tài)。所以,后面的then語(yǔ)句都變成針對(duì)后者p1.又過(guò)了2秒,p1變?yōu)閞ejected,導(dǎo)致觸發(fā)catch方法指定的回調(diào)函數(shù)。
注意:調(diào)用resolve或reject并不會(huì)終結(jié)Promise的參數(shù)函數(shù)的執(zhí)行。
new Promise((resolve,reject)=>{ resolve(1); console.log(2); }).then(r=>{ console.log(r); });
上面代碼中,調(diào)用resolve(1)以后,后面的console.log(2)還是會(huì)執(zhí)行,并且會(huì)首先打印出來(lái)。這是因?yàn)榱⒓磖esolved的Promise是在本輪事件循環(huán)的末尾執(zhí)行,總是晚于本輪循環(huán)的同步任務(wù)。
一般來(lái)說(shuō),調(diào)用resolve或reject以后,Promise的使命就完成了,后繼操作應(yīng)該放到then方法里面,而不應(yīng)該直接寫在resolve或reject的后面。所以,最好在它們前面加上return語(yǔ)句,這樣就不會(huì)有意外。
new Promise((resolve,reject)=>{ return resolve(1); //后面的語(yǔ)句不會(huì)執(zhí)行 console.log(2); })
demo小例子:
let info =[]; function dog(){ return new Promise(function(resolve,reject){ resolve("一只狗"); }) }; function cat(){ return new Promise(function(resolve,reject){ resolve("一只貓"); }) }; function animal(num){ return new Promise(function(resolve,reject){ info.push(num); console.log(info); resolve(); }) }; dog().then(animal).then(cat).then(animal); //["一只狗"] //["一只狗","一只貓"]Promise.prototype.then()
Promise實(shí)例具有then方法,也就是說(shuō),then方法是定義在原型對(duì)象Promise.prototype上的。它的作用是為Promsie實(shí)例添加狀態(tài)改變時(shí)的回調(diào)函數(shù)。前面說(shuō)過(guò),then方法的第一個(gè)參數(shù)是resolved狀態(tài)的回調(diào)函數(shù),第二個(gè)參數(shù)是rejected狀態(tài)的回調(diào)函數(shù)。
then方法返回的是一個(gè)新的Promise實(shí)例(注意,不是原來(lái)那個(gè)Promise實(shí)例)。因此可以采用鏈?zhǔn)綄懛ǎ磘hen方法后面再調(diào)用另一個(gè)then方法。
getJson("./index.json").then(function(json){ return json.post; }).then(function(post){ //... });
上面代碼使用then方法,依次指定了兩個(gè)回調(diào)函數(shù)。第一個(gè)回調(diào)函數(shù)完成后,會(huì)將返回結(jié)果作為參數(shù),傳入第二個(gè)回調(diào)函數(shù)。
采用鏈?zhǔn)降膖hen,可以指定一組按照次序調(diào)用的回調(diào)函數(shù)。這時(shí),前一個(gè)回調(diào)函數(shù),有可能返回的還是一個(gè)Promise對(duì)象,這時(shí)后一個(gè)回調(diào)函數(shù),就會(huì)等待該P(yáng)romise對(duì)象的狀態(tài)發(fā)生變化,才會(huì)被調(diào)用。
getJson("/index.jspn").then(function(post){ return getJson(post.commentURL); }).then(function funcA(comments){ console.log("resolved",comments); },function funcB(err){ console.log("rejected",err) })
上面代碼中,第一個(gè)then方法指定的回調(diào)函數(shù),返回的是另一個(gè)Promise對(duì)像。這時(shí),第二個(gè)then方法指定的回調(diào)函數(shù),就會(huì)等待這個(gè)新的Promise對(duì)象狀態(tài)發(fā)生變化。如果變?yōu)閞esolved,就調(diào)用funcA,如果狀態(tài)變?yōu)閞ejected,就調(diào)用funcB.
Promise.prototype.catch()Promise.prototype.catch方法是.then(null,rejection)的別名,用于指定發(fā)生錯(cuò)誤時(shí)的回調(diào)函數(shù)。
getJSON("/posts.json").then(function(posts){ //.... }).catch(function(error){ //處理getJSON和前一個(gè)回調(diào)函數(shù)運(yùn)行時(shí)發(fā)生的錯(cuò)誤。 console.log("發(fā)生錯(cuò)誤!",error) });
上面代碼中,getJSON方法返回一個(gè)Promise對(duì)象,如果該對(duì)象狀態(tài)變?yōu)閞esolved,則會(huì)調(diào)用then方法指定的回調(diào)函數(shù);如果異步操作拋出錯(cuò)誤,狀態(tài)就會(huì)變?yōu)閞ejected,就會(huì)調(diào)用catch方法指定的回調(diào)函數(shù),處理這個(gè)錯(cuò)誤。另外then方法指定的回調(diào)函數(shù),如果運(yùn)行中拋出錯(cuò)誤,也會(huì)被catch方法捕獲。
p.then((val)=>console.log("fulid",val)) .catch((err)=>console.log("reject",err));Promise.prototype.finally()
finally方法用于指定不管Promise對(duì)象最后狀態(tài)如何,都會(huì)執(zhí)行操作。該方法是ES2018引入標(biāo)準(zhǔn)的。
promise.then(result=>{...}) .catch(error=>{...}) .finally(()=>{...})
上面代碼中,不管promise最后的狀態(tài),在執(zhí)行完then或catch指定的回調(diào)函數(shù)以后,都會(huì)執(zhí)行finally方法指定的回調(diào)函數(shù)。
下面是一個(gè)例子,服務(wù)器使用Promise處理請(qǐng)求,然后使用finally方法關(guān)掉服務(wù)器。
server.listen(port).then(function(){ //... }).finally(server.stop);
finally方法的回調(diào)函數(shù)不接受任何參數(shù),這意味著沒(méi)有辦法知道,前面的Promise狀態(tài)到底是fulfilled還是rejected。這表明,finally方法里面的操作,應(yīng)該是與狀態(tài)無(wú)關(guān)的,不依賴于Promise的執(zhí)行結(jié)果。
finally本質(zhì)上是then方法的特例。
Promise.all方法用于將多個(gè)Promise實(shí)例,包裝成一個(gè)新的promise實(shí)例。
const p = Promise.all([p1,p2,p3]);
上面代碼中,Promise.all方法接受一個(gè)數(shù)組作為參數(shù),p1,p2,p3都是Promise實(shí)例,如果不是,就會(huì)先調(diào)用下面講到的Promise.resolve方法,將參數(shù)轉(zhuǎn)為Promise實(shí)例,再進(jìn)一步處理。
p的我狀態(tài)由p1,p2,p3決定,分成兩種情況。
(1)只有p1,p2,p3的狀態(tài)都變成fulfilled,p的狀態(tài)才會(huì)變成fulfilled,此時(shí)p1,p2,p3的返回值組成一個(gè)數(shù)組,傳遞給p的回調(diào)函數(shù)。
(2)只要p1,p2,p3之中有一個(gè)被rejected,p的狀態(tài)就變成rejected,此時(shí)第一個(gè)被reject的實(shí)例的返回值,會(huì)傳遞給p的回調(diào)函數(shù)。
demo
const a = contentData(); const b = a.then(findAll); const c = a.then(getCurrent); Promise.all([ b, c ]).then(([books, user]) => pickTopRecommentations(books, user))
上面代碼中,b和c是兩個(gè)異步操作,只有等到它們的結(jié)果都返回了,才會(huì)觸發(fā)pickTopRecommentations這個(gè)回調(diào)函數(shù)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/99463.html
摘要:下一篇大概就是源碼方面的學(xué)習(xí)筆記了龜速學(xué)習(xí)中這一次我是去看了下規(guī)范照例傳送門圖靈社區(qū)規(guī)范首先吧個(gè)人總結(jié)下該用的詞解決結(jié)婚拒絕婉拒終值值傳家寶拒因好人卡等等異常車禍理下概念我們的的就像是一場(chǎng)姻緣對(duì)吧解決呢就是結(jié)婚成功啦傳家寶也如愿的傳給下一代 下一篇大概就是源碼方面的學(xué)習(xí)筆記了...龜速學(xué)習(xí)中... 這一次我是去看了下Promises/A+規(guī)范照例傳送門:圖靈社區(qū)Promises/A+規(guī)...
摘要:版本以及之前,本身還沒(méi)有異步執(zhí)行代碼的能力,宿主環(huán)境傳遞給引擎,然后按順序執(zhí)行,由宿主發(fā)起任務(wù)。采納引擎術(shù)語(yǔ),把宿主發(fā)起的任務(wù)稱為宏觀任務(wù),把引擎發(fā)起的任務(wù)稱為微觀任務(wù)。基本用法示例的回調(diào)是一個(gè)異步的執(zhí)行過(guò)程。 筆記說(shuō)明 重學(xué)前端是程劭非(winter)【前手機(jī)淘寶前端負(fù)責(zé)人】在極客時(shí)間開的一個(gè)專欄,每天10分鐘,重構(gòu)你的前端知識(shí)體系,筆者主要整理學(xué)習(xí)過(guò)程的一些要點(diǎn)筆記以及感悟,完整的...
摘要:版本以及之前,本身還沒(méi)有異步執(zhí)行代碼的能力,宿主環(huán)境傳遞給引擎,然后按順序執(zhí)行,由宿主發(fā)起任務(wù)。采納引擎術(shù)語(yǔ),把宿主發(fā)起的任務(wù)稱為宏觀任務(wù),把引擎發(fā)起的任務(wù)稱為微觀任務(wù)。基本用法示例的回調(diào)是一個(gè)異步的執(zhí)行過(guò)程。 筆記說(shuō)明 重學(xué)前端是程劭非(winter)【前手機(jī)淘寶前端負(fù)責(zé)人】在極客時(shí)間開的一個(gè)專欄,每天10分鐘,重構(gòu)你的前端知識(shí)體系,筆者主要整理學(xué)習(xí)過(guò)程的一些要點(diǎn)筆記以及感悟,完整的...
摘要:版本以及之前,本身還沒(méi)有異步執(zhí)行代碼的能力,宿主環(huán)境傳遞給引擎,然后按順序執(zhí)行,由宿主發(fā)起任務(wù)。采納引擎術(shù)語(yǔ),把宿主發(fā)起的任務(wù)稱為宏觀任務(wù),把引擎發(fā)起的任務(wù)稱為微觀任務(wù)。基本用法示例的回調(diào)是一個(gè)異步的執(zhí)行過(guò)程。 筆記說(shuō)明 重學(xué)前端是程劭非(winter)【前手機(jī)淘寶前端負(fù)責(zé)人】在極客時(shí)間開的一個(gè)專欄,每天10分鐘,重構(gòu)你的前端知識(shí)體系,筆者主要整理學(xué)習(xí)過(guò)程的一些要點(diǎn)筆記以及感悟,完整的...
摘要:異步操作未完成異步操作成功異步操作失敗基本用法是一個(gè)構(gòu)造函數(shù),接收一個(gè)參數(shù),這個(gè)參數(shù)是函數(shù),同時(shí)這個(gè)參數(shù)函數(shù)要傳入兩個(gè)參數(shù),,分別表示異步操作執(zhí)行成功后的回調(diào)函數(shù)和異步操作執(zhí)行失敗后的回調(diào)函數(shù)。如果調(diào)用函數(shù),就會(huì)調(diào)用方法的第一個(gè)參數(shù)。 Promise對(duì)象 Promise 表示一個(gè)異步操作的最終結(jié)果,與之進(jìn)行交互的方式主要是 then 方法,該方法注冊(cè)了兩個(gè)回調(diào)函數(shù),用于接收 promi...
閱讀 917·2021-11-24 09:38
閱讀 925·2021-11-23 09:51
閱讀 2939·2021-11-16 11:44
閱讀 1762·2021-09-22 15:52
閱讀 1626·2021-09-10 11:20
閱讀 1361·2019-08-30 13:47
閱讀 1292·2019-08-29 12:36
閱讀 3293·2019-08-26 10:43