最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

一首歌帶你搞懂Promise

2021-12-16 12:02 作者:千鋒教育  | 我要投稿

Promise簡介

Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強(qiáng)大。(摘自<ECMAScript 6 入門>),但是對于Promise的創(chuàng)建和執(zhí)行流程,其實(shí)有很多人初學(xué)時(shí),容易走入誤區(qū)。

今天就以一首歌來帶大家學(xué)習(xí)Promise。

Promise創(chuàng)建

Promise翻譯過來的意思就是"承諾",其實(shí)Promise的創(chuàng)建本質(zhì)就是一個(gè)許下承諾的過程,想到這我的腦海中不由得浮現(xiàn)了一首經(jīng)典老歌,海鳴威 《你的承諾》。

歌中相知相戀的兩個(gè)人,奈何情深緣淺,終于還是分開,許下了“不為彼此難過, 過各自的生活"這樣的承諾。但是隨后歌曲又以"Oh baby 你答應(yīng)我的我都記得 ,但是你卻忘了你的承諾 ,不是說好彼此都不再聯(lián)絡(luò), 誰都別再犯錯(cuò)",暗示承諾的狀態(tài)發(fā)生改變。

由此不難想象以下兩種情況:

  1. 遵守承諾

2.違背承諾


同樣,JS中的Promise的創(chuàng)建也是許下代碼承諾的一種方式,它默認(rèn)也包含三種狀態(tài):pending ?(進(jìn)行中)

  1. pending ?(進(jìn)行中)

  2. fulfilled(已成功)

  3. rejected(已失敗)

那么如何許下JS中的承諾呢:

Promise中接收一個(gè)回調(diào)函數(shù)(簡單說就是一個(gè)容器),傳入某個(gè)未來才會結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果;此時(shí)打印,你會得到一個(gè)Promise實(shí)例(實(shí)例化對象),展開之后默認(rèn)顯示:

此時(shí)我們會看到

[[PromiseState]]用于存儲Promise實(shí)例(當(dāng)前承諾)的狀態(tài) ,默認(rèn)顯示pending ;

[[PromiseResult]]用于表示Promise實(shí)例中存儲的數(shù)據(jù) , 默認(rèn)顯示undefined;

[[Prototype]]表示原型 以后再做講解

但是有人就會問了,既然有三種狀態(tài),而默認(rèn)是pending(進(jìn)行中)狀態(tài),那么我們?nèi)绾螌?dāng)前Promise實(shí)例的狀態(tài)改為另外兩種:

這就不得不提到Promise的第一特征了:對象的狀態(tài)不受外界影響。Promise對象代表一個(gè)異步操作,有三種狀態(tài):pending(進(jìn)行中)、fulfilled(已成功)和rejected(已失?。V挥挟惒讲僮鞯慕Y(jié)果,可以決定當(dāng)前是哪一種狀態(tài),任何其他操作都無法改變這個(gè)狀態(tài)。

可以理解為,狀態(tài)并不是自行改變的,而是由異步(同步也可以)的結(jié)果決定了.。

所以Promise在創(chuàng)建過程中,傳入的回調(diào)函數(shù)接收了改變狀態(tài)的兩個(gè)方法 ,resolve,reject作為形式參數(shù)傳入.

resolve() ?將Promise實(shí)例的狀態(tài) ?由pending(進(jìn)行中) 改為 fulfilled(已成功)

reject() ? ?將Promise實(shí)例的狀態(tài) ?由pending(進(jìn)行中) 改為rejected(已失敗)

而且resolve() ?reject() 方法在調(diào)用時(shí) 還可以接收一個(gè)參數(shù),作為數(shù)據(jù)傳入,存儲到Promise實(shí)例中。

同步代碼展示:

resolve() 和 reject() 方法,在同步代碼中調(diào)用,會立即改變Promise實(shí)例的狀態(tài)。

異步代碼展示:

resolve() 和 reject() 方法,在異步代碼中調(diào)用:由于JS是單線程,會優(yōu)先在主線程執(zhí)行同步代碼,異步代碼會放到任務(wù)隊(duì)列中,所以在頁面加載時(shí),,Promise實(shí)例為pending(進(jìn)行中)狀態(tài),等待主線程執(zhí)行完畢,任務(wù)隊(duì)列通知主線程,異步任務(wù)可以執(zhí)行了,該任務(wù)才會進(jìn)入主線程執(zhí)行。

此時(shí)setTimeout中的回調(diào)函數(shù)被調(diào)用,執(zhí)行了resolve() 或 reject() 方法, Promise實(shí)例會隨之改變狀態(tài),并存儲傳入的數(shù)據(jù)。

那么resolve() reject() 方法,可以重復(fù)調(diào)用么?

這就要講到Promise的第二大特征:一旦狀態(tài)改變,就不會再變,任何時(shí)候都可以得到這個(gè)結(jié)果。Promise對象的狀態(tài)改變,只有兩種可能:從pending變?yōu)閒ulfilled和從pending變?yōu)閞ejected。只要這兩種情況發(fā)生,狀態(tài)就凝固了,不會再變了,會一直保持這個(gè)結(jié)果,這時(shí)就稱為 resolved(已定型) 注意,為了行文方便,本章后面的resolved統(tǒng)一只指fulfilled狀態(tài),不包含rejected狀態(tài)。

由此可見Promise本質(zhì),就是一個(gè)狀態(tài)機(jī),當(dāng)該P(yáng)romise對象創(chuàng)建出來之后,其狀態(tài)就是pending(進(jìn)行中),然后通過程序來控制到底是執(zhí)行已完成,還是執(zhí)行已失敗。

因?yàn)镻romise處理的是異步任務(wù),所以我們還得對Promise做監(jiān)聽,當(dāng)Promise的狀態(tài)發(fā)生變化時(shí),我們要執(zhí)行相應(yīng)的函數(shù)(then ?catch ? finally)。


Promise的動態(tài)方法

所謂Promise動態(tài)方法,即將封裝的方法存儲在Promise的原型對象(prototype)上,供所有通過構(gòu)造函數(shù)創(chuàng)建的實(shí)例化對象使用。

Promise.prototype.then()

Promise 實(shí)例具有then方法,它的作用是為 Promise 實(shí)例添加狀態(tài)改變時(shí)的回調(diào)函數(shù),前面說過 Promise實(shí)例的狀態(tài)可以從pending(進(jìn)行中) 變?yōu)?fulfilled(已成功)或rejected(已失敗),所以then方法中接收兩個(gè)回調(diào)函數(shù)(它們都是可選的)。

p.then(resolveHandler,rejectHandler)

resolveHandler ?第一參數(shù),用于指定Promise實(shí)例,由pending(進(jìn)行中) 變?yōu)?fulfilled(已成功)時(shí)執(zhí)行的回調(diào)函數(shù)。

rejectHandler ? ? 第二參數(shù),用于指定Promise實(shí)例,由pending(進(jìn)行中) 變?yōu)?rejected(已失敗)時(shí)執(zhí)行的回調(diào)函數(shù)。

可以理解為 ?then()方法中的兩個(gè)回調(diào)函數(shù),提前規(guī)定好了狀態(tài)改變時(shí)需要執(zhí)行的內(nèi)容,等待以后Promise實(shí)例的狀態(tài)之后再執(zhí)行對應(yīng)的回調(diào)函數(shù) (本質(zhì)還是回調(diào)函數(shù),要用魔法打敗魔法)。

注意:resolveHandler ? rejectHandler ?中可以傳入一個(gè)形式參數(shù) 接收Promise實(shí)例中存儲數(shù)據(jù)。

解析:在異步代碼中調(diào)用: 由于JS是單線程,會優(yōu)先在主線程執(zhí)行同步代碼,異步代碼會放到任務(wù)隊(duì)列中,所以

  1. Promise創(chuàng)建完畢,Promise實(shí)例為pending(進(jìn)行中)狀態(tài);

  2. 調(diào)用 then()方法,傳入兩個(gè)回調(diào)函數(shù),提前規(guī)定好了狀態(tài)改變時(shí)需要執(zhí)行的內(nèi)容,等待以后Promise實(shí)例的狀態(tài)之后再執(zhí)行對應(yīng)的回調(diào)函數(shù);

  3. 等待主線程執(zhí)行完畢,任務(wù)隊(duì)列通知主線程,異步任務(wù)可以執(zhí)行了,該任務(wù)才會進(jìn)入主線程執(zhí)行。=> 隨機(jī)一個(gè)0-1的隨機(jī)數(shù),根據(jù)結(jié)果改變Promise實(shí)例的狀態(tài) ,存儲傳入的數(shù)據(jù) => 執(zhí)行then方法中對應(yīng)的回調(diào)函數(shù)。

還有一個(gè)有趣的地方:then方法返回的是一個(gè)新的Promise實(shí)例(注意,不是原來那個(gè)Promise實(shí)例)。因此可以采用鏈?zhǔn)綄懛ǎ磘hen方法后面再調(diào)用另一個(gè)then方法。

上面的代碼使用then方法,依次指定了兩個(gè)回調(diào)函數(shù)。第一個(gè)回調(diào)函數(shù)完成以后,會將返回結(jié)果作為參數(shù),傳入第二個(gè)回調(diào)函數(shù)。當(dāng)然這里有一個(gè)前提,那就是Promise實(shí)例的狀態(tài)為已成功且代碼執(zhí)行過程中不出錯(cuò)的情況下。萬一出錯(cuò)的話,那我們就可以使用then()方法的第二個(gè)回調(diào)函數(shù)或者catch()方法捕獲錯(cuò)誤。


Promise.prototype.catch()

catch()方法是.then(null, rejection)或.then(undefined, rejection)的別名,用于指定發(fā)生錯(cuò)誤時(shí)的回調(diào)函數(shù)。

上面代碼中,readText()方法返回一個(gè) Promise 對象,如果該對象狀態(tài)變?yōu)閞esolved,則會調(diào)用then()方法指定的回調(diào)函數(shù);如果異步操作拋出錯(cuò)誤,狀態(tài)就會變?yōu)閞ejected,就會調(diào)用catch()方法指定的回調(diào)函數(shù),處理這個(gè)錯(cuò)誤。另外,then()方法指定的回調(diào)函數(shù),如果運(yùn)行中拋出錯(cuò)誤,也會被catch()方法捕獲。

then和catch的鏈?zhǔn)讲僮?/p>

then()和catch()配合使用,實(shí)現(xiàn)的鏈?zhǔn)讲僮餍Ч选?/p>

上面的代碼使用then catch方法進(jìn)行鏈?zhǔn)秸{(diào)用,依次指定了三個(gè)then()的回調(diào)函數(shù)以及一個(gè)catch()的回調(diào)函數(shù)。第一個(gè)回調(diào)函數(shù)完成以后,會將返回結(jié)果作為參數(shù),傳入第二個(gè)回調(diào)函數(shù),同樣第二個(gè)回調(diào)函數(shù)完成后,會將返回結(jié)果作為參數(shù),傳入第三個(gè)回調(diào)函數(shù),以此類推。當(dāng)然這里同樣也有一個(gè)前提,那就是Promise實(shí)例的狀態(tài)為已成功且代碼執(zhí)行過程中不出錯(cuò)的情況下。萬一出錯(cuò)的話,那catch()方法剛好捕獲鏈?zhǔn)讲僮鬟^程中出現(xiàn)的錯(cuò)誤。

如果then方法中回調(diào)函數(shù)的返回值也是一個(gè)Promise實(shí)例;

上面代碼中,第一個(gè)then方法指定的回調(diào)函數(shù),返回的是另一個(gè)Promise對象。這時(shí),第二個(gè)then方法指定的回調(diào)函數(shù),就會等待這個(gè)新的Promise對象狀態(tài)發(fā)生變化。如果變?yōu)閞esolved,繼續(xù)鏈?zhǔn)秸{(diào)用后面then方法中指定的回調(diào)函數(shù),如果狀態(tài)變?yōu)閞ejected,就會被catch方法捕獲。

注意:Promise 實(shí)例的錯(cuò)誤具有“冒泡”性質(zhì),會一直向后傳遞,直到被捕獲為止。也就是說,錯(cuò)誤總是會被下一個(gè)catch語句捕獲。

Promise的靜態(tài)方法

所謂Promise靜態(tài)方法,即將封裝的方法存儲在構(gòu)造函數(shù)Promise上,由構(gòu)造函數(shù)自身調(diào)用。

Promise.all

Promise.all()方法用于將多個(gè) Promise 實(shí)例,包裝成一個(gè)新的 Promise 實(shí)例。

const p = Promise.all([p1, p2, p3]);

相較于then方法的鏈?zhǔn)讲僮鳎琍romise.all()更注重并發(fā),即依次按順序發(fā)送多個(gè)請求,等待所有的請求均有結(jié)果之后,對應(yīng)請求順序?qū)?shù)據(jù)依次存放到數(shù)組中返回。

通過以上代碼可以發(fā)現(xiàn): (摘自ECMAScript 6 入門)

Promise.all()方法接受一個(gè)數(shù)組作為參數(shù),p1、p2、p3都是 Promise 實(shí)例,如果不是,就會先調(diào)用下面講到的Promise.resolve方法,將參數(shù)轉(zhuǎn)為 Promise 實(shí)例,再進(jìn)一步處理。另外,Promise.all()方法的參數(shù)可以不是數(shù)組,但必須具有 Iterator 接口,且返回的每個(gè)成員都是 Promise 實(shí)例。

p的狀態(tài)由p1、p2、p3決定,分成兩種情況。

(1)只有p1、p2、p3的狀態(tài)都變成fulfilled,p的狀態(tài)才會變成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í)例的返回值,會傳遞給p的回調(diào)函數(shù)。

Promise.race

Promise.race()方法同樣是將多個(gè) Promise 實(shí)例,包裝成一個(gè)新的 Promise 實(shí)例。

相較于Promise.all方法, Promise.race方法更側(cè)重狀態(tài)改變的速度。

通過以上代碼可以發(fā)現(xiàn): (摘自ECMAScript 6 入門)


只要p1、p2、p3之中有一個(gè)實(shí)例率先改變狀態(tài),p的狀態(tài)就跟著改變。那個(gè)率先改變的 Promise 實(shí)例的返回值,就傳遞給p的回調(diào)函數(shù)。

Promise.allSettled

Promise.allSettled()方法同樣是將多個(gè) Promise 實(shí)例,包裝成一個(gè)新的 Promise 實(shí)例。

相較于Promise.all方法,Promise.allSettled跟注重于不管每一個(gè)Promise實(shí)例是成功還是失敗,都會將結(jié)果依次按請求順序放到數(shù)組中。

值得注意的地方時(shí),在將數(shù)據(jù)放到數(shù)組的過程中,傳入的Promise實(shí)例的狀態(tài)不同,放置的結(jié)果稍有不同(數(shù)組中的每個(gè)成員是一個(gè)對象,對象的格式是固定的)。

成員對象的status屬性的值只可能是字符串fulfilled或字符串rejected,用來區(qū)分異步操作是成功還是失敗。如果是成功(fulfilled),對象會有value屬性,如果是失?。╮ejected),會有reason屬性,對應(yīng)兩種狀態(tài)時(shí)前面異步操作的返回值。

總結(jié)

有了Promise對象,就可以將異步操作以同步操作的流程表達(dá)出來,避免了層層嵌套的回調(diào)函數(shù)。此外,Promise對象提供統(tǒng)一的接口,使得控制異步操作更加容易。

Promise也有一些缺點(diǎn)。首先,無法取消Promise,一旦新建它就會立即執(zhí)行,無法中途取消。其次,如果不設(shè)置回調(diào)函數(shù),Promise內(nèi)部拋出的錯(cuò)誤,不會反應(yīng)到外部。第三,當(dāng)處于pending狀態(tài)時(shí),無法得知目前進(jìn)展到哪一個(gè)階段(剛剛開始還是即將完成)。

升級用法 async await

ES2017 標(biāo)準(zhǔn)引入了 async 函數(shù),使得異步操作變得更加方便。

async 函數(shù)是什么?一句話,它就是 Generator 函數(shù)的語法糖。

基本用法

async函數(shù)的返回值也是一個(gè)Promise實(shí)例,在async函數(shù)執(zhí)行的過程中,一旦遇到await就會先返回pending(進(jìn)行中)狀態(tài)的Promise實(shí)例,等待異步操作有結(jié)果之后,繼續(xù)執(zhí)行await之后的語句,依次類推,語句全部執(zhí)行完畢且無錯(cuò)誤的情況下,則返回的Promise實(shí)例會變?yōu)橐殉晒?,否則會變?yōu)橐咽 ?/p>

你學(xué)會了么?文章底部留言告訴我喲!


一首歌帶你搞懂Promise的評論 (共 條)

分享到微博請遵守國家法律
桓仁| 绥化市| 吴江市| 临漳县| 固阳县| 稷山县| 徐水县| 曲松县| 潞西市| 柳江县| 城口县| 洞口县| 南华县| 广州市| 永新县| 黄浦区| 定安县| 青阳县| 卢湾区| 绥江县| 定安县| 汤阴县| 彭水| 张家口市| 民乐县| 安义县| 松桃| 新河县| 石门县| 和平区| 罗山县| 广西| 马公市| 南康市| 昆明市| 洞头县| 武隆县| 乌苏市| 巨鹿县| 阿瓦提县| 花垣县|