深入了解 Promise

Promise 必須為三種狀態(tài)之一死嗦, 等待態(tài)Pending褒繁、執(zhí)行態(tài)Fulfilled和拒絕態(tài)Rejected犬庇。一旦Promise被resolve或reject俯渤,便不能再遷移至其他任何狀態(tài)呆细,即狀態(tài)不可改變immutable

基本執(zhí)行過程:

  1. 初始化Promise狀態(tài)(pending)
  2. 立即執(zhí)行Promise中傳入的Fn函數(shù)八匠,將Promise內(nèi)部resolve絮爷、reject函數(shù)作為參數(shù)傳遞給Fn,然后按照事件機(jī)制時(shí)機(jī)處理梨树。
  3. 執(zhí)行then方法注冊(cè)回調(diào)處理數(shù)據(jù)(then方法可被同一個(gè)promise調(diào)用多次)
  4. Promise關(guān)鍵是要保證then方法傳入的參數(shù) onFulfilled 和 onRejected, 必須在then方法被調(diào)用的那一輪事件循環(huán)之后的新執(zhí)行棧中執(zhí)行坑夯。

鏈?zhǔn)秸{(diào)用

鏈?zhǔn)絇romise是指在當(dāng)前Promise 達(dá)到fulfilled狀態(tài)后,即開始執(zhí)行下一個(gè)Promise抡四。

  • 例子1:
new Promise(function(resolve,reject){
  setTimeout(_ => {
    resolve(1);
    resolve(3);
    reject('error');
  },1000)
}).then(res => {
  console.log(res);
}).then(res => {
  console.log(res);
}).then(res => {
  console.log(res);
});
// 1
// undefiend
// undefiend

結(jié)果輸出不同的data, 由此可以看出:

  1. 可以進(jìn)行鏈?zhǔn)秸{(diào)用柜蜈, 一個(gè)Promise可以有多個(gè)then()
  2. 只輸出第一次resolve的值,reject沒有輸出指巡, 由此可見 Promise的狀態(tài)只可以由 \color{red}{pending > fulfilled} 或者 \color{red}{pending > rejected},是不可逆的淑履。
  3. then中返回了新的Promise, 但是then中注冊(cè)的回調(diào)仍然屬于上一個(gè)Promise的。
  • 例子2:
function test() {
  return new Promise((resolve, reject) => {
    setTimeout(_ => {
      resolve(2);
    }, 100)
  })
}
new Promise((resolve, reject) => {
  setTimeout(_ => {
    resolve(1);
  }, 100);
}).then(res => {
  console.log(res);
  return test();
}).then(res => {
  console.log(res);
});
// 1
// 2

當(dāng)Promise的狀態(tài)變?yōu)閒ulfilled之后會(huì)執(zhí)行其回調(diào)函數(shù)厌处, 而回調(diào)函數(shù)里返回下一個(gè)Promise,并且fulfilled時(shí)鳖谈,然后執(zhí)行其回調(diào)岁疼, 以此類推下去... 鏈?zhǔn)秸{(diào)用的效果就出來(lái)了阔涉。

上例中, test里面創(chuàng)建的Promise捷绒,它是沒有調(diào)用then方法的瑰排。 所上分析得出Promise的回調(diào)函數(shù)是通過調(diào)用其then方法注冊(cè)的, 因此test方法創(chuàng)建的Promise其回調(diào)函數(shù)為空暖侨。顯然如果沒有回調(diào)函數(shù)椭住,執(zhí)行resolve的時(shí)候, 是沒辦法鏈?zhǔn)秸{(diào)用的字逗, 因此京郑, 我們需要主動(dòng)為其注入回調(diào)函數(shù)。

異常處理

異常通常是指在執(zhí)行成功或失敗回調(diào)時(shí)代碼出錯(cuò)產(chǎn)生的錯(cuò)誤葫掉, 對(duì)于這類異常些举, 使用 catch 來(lái)捕獲錯(cuò)誤, 并將Promise設(shè)為rejected狀態(tài)即可俭厚。

new Promise((resolve, reject) => {
  setTimeout(_ => {
    resolve(1);
  }, 100);
}).then(res => {
  console.log(res);
}).catch(err => {
  console.log('err:'+ err);
});

resolve 方法和reject方法

實(shí)際應(yīng)用中户魏, 我們可以使用Promise.resolve 和 Promise.reject方法, 用于將非Promise實(shí)例包裝為Promise實(shí)例。

Promise.resolve('success');
Promise.reject('error');
//等同于
new Promise(resolve => resolve('success'));
new Promise((resolve,reject) => reject('error'));

這些情況下叼丑, Promise.resolve的入?yún)⒖赡苡幸幌聨追N情況:

  • 無(wú)參數(shù)(直接返回一個(gè)resolved狀態(tài)的Promise對(duì)象)
  • 普通數(shù)據(jù)對(duì)象 (直接返回一個(gè)resolve狀態(tài)的Promise對(duì)象)
  • 一個(gè)Promise實(shí)例 (直接返回當(dāng)前實(shí)例)
  • 一個(gè)thenable對(duì)象关翎,thenable對(duì)象是具有then方法的對(duì)象(轉(zhuǎn)化為Promise對(duì)象,并立即執(zhí)行thenable對(duì)象的then方法)

Promise.all

Promise.all 參數(shù)是一個(gè)Promise的數(shù)組鸠信, 只有當(dāng)所有的Promise的狀態(tài)都轉(zhuǎn)為fulfilled,才會(huì)執(zhí)行then方法纵寝, 當(dāng)有一個(gè)失敗,都會(huì)進(jìn)入catch被捕獲錯(cuò)誤。Promise.all執(zhí)行成功返回的結(jié)果是每個(gè)Promise返回結(jié)果組成的數(shù)組星立,如果失敗則返回第一個(gè)reject的結(jié)果店雅。
Promise.all會(huì)阻塞一起執(zhí)行的Promise,因此需在必要的業(yè)務(wù)場(chǎng)景來(lái)使用

function test() {
 return new Promise((resolve, reject) => {
   setTimeout(_ => {
     resolve(1);
   },100)
 })
}
function test2() {
 return new Promise((resolve, reject) => {
   setTimeout(_ => {
     resolve(2)
   },1)
 })
}
function test3() {
 return new Promise((resolve, reject) => {
   setTimeout(_ => {
     resolve(3);
   },300)
 })
}

Promise.all([test(),test2(),test3()]).then(res => {
  console.log(res);  // [1,2,3]
})

入?yún)⑹且粋€(gè)Promise的實(shí)例數(shù)組, 然后注冊(cè)一個(gè)then方法贞铣,然后是數(shù)組中的Promise實(shí)例的狀態(tài)都轉(zhuǎn)為fulfilled之后執(zhí)行then方法闹啦。 這里主要就是一個(gè)計(jì)數(shù)邏輯, 每當(dāng)一個(gè)Promise的狀態(tài)變?yōu)閒ulfilled之后就保存該實(shí)例返回的數(shù)據(jù)辕坝,然后將計(jì)數(shù)減一窍奋, 當(dāng)計(jì)數(shù)器變?yōu)?的時(shí)候, 代表數(shù)組中所有的Promise實(shí)例都執(zhí)行完畢

Promise.race

Promise.race也會(huì)調(diào)用所有的Promise實(shí)例酱畅, 其和Promise.all的不同點(diǎn)是琳袄, 返回結(jié)果是所有Promise實(shí)例最先執(zhí)行完的那個(gè)Promise的結(jié)果,不關(guān)心成功還是失敗纺酸。

function test() {
 return new Promise((resolve, reject) => {
   setTimeout(_ => {
     resolve(1);
   },100)
 })
}
function test2() {
 return new Promise((resolve, reject) => {
   setTimeout(_ => {
     resolve(2)
   },1)
 })
}
function test3() {
 return new Promise((resolve, reject) => {
   setTimeout(_ => {
     resolve(3);
   },300)
 })
}

Promise.race([test(),test2(),test3()]).then(res => {
  console.log(res); // 2
})

有了Promise.all的理解窖逗, Promise.race理解起來(lái)就更容易了。它的入?yún)⒁彩且粋€(gè)Promise實(shí)例數(shù)組餐蔬, 然后其then注冊(cè)的回調(diào)方法是數(shù)組中的某一個(gè)Promise的狀態(tài)為fulfilled的時(shí)候執(zhí)行碎紊。因?yàn)镻romise的狀態(tài)只能改變一次,那么我們只需要把Promise.race中產(chǎn)生的Promise對(duì)象的resolve方法樊诺,注入到數(shù)組中的每一個(gè)Promise實(shí)例中的回調(diào)函數(shù)中即可仗考。

雖然then普遍被認(rèn)為是微任務(wù)。 但是瀏覽器沒辦法模擬微任務(wù)词爬, 目前使用setTimeout替代秃嗜, promise的polyfill(es6-promise)里用的也是setTimeout。因此這里直接使用setTimeout,以宏任務(wù)代替了微任務(wù)顿膨。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末锅锨,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子恋沃,更是在濱河造成了極大的恐慌必搞,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,865評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芽唇,死亡現(xiàn)場(chǎng)離奇詭異顾画,居然都是意外死亡取劫,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門研侣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)谱邪,“玉大人,你說我怎么就攤上這事庶诡〉胍” “怎么了?”我有些...
    開封第一講書人閱讀 169,631評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵末誓,是天一觀的道長(zhǎng)扯俱。 經(jīng)常有香客問我,道長(zhǎng)喇澡,這世上最難降的妖魔是什么迅栅? 我笑而不...
    開封第一講書人閱讀 60,199評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮晴玖,結(jié)果婚禮上读存,老公的妹妹穿的比我還像新娘。我一直安慰自己呕屎,他們只是感情好让簿,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,196評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著秀睛,像睡著了一般尔当。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蹂安,一...
    開封第一講書人閱讀 52,793評(píng)論 1 314
  • 那天椭迎,我揣著相機(jī)與錄音,去河邊找鬼藤抡。 笑死侠碧,一個(gè)胖子當(dāng)著我的面吹牛抹估,可吹牛的內(nèi)容都是我干的缠黍。 我是一名探鬼主播,決...
    沈念sama閱讀 41,221評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼药蜻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼瓷式!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起语泽,我...
    開封第一講書人閱讀 40,174評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤贸典,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后踱卵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體廊驼,經(jīng)...
    沈念sama閱讀 46,699評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡据过,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,770評(píng)論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了妒挎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绳锅。...
    茶點(diǎn)故事閱讀 40,918評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖酝掩,靈堂內(nèi)的尸體忽然破棺而出鳞芙,到底是詐尸還是另有隱情,我是刑警寧澤期虾,帶...
    沈念sama閱讀 36,573評(píng)論 5 351
  • 正文 年R本政府宣布原朝,位于F島的核電站,受9級(jí)特大地震影響镶苞,放射性物質(zhì)發(fā)生泄漏喳坠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,255評(píng)論 3 336
  • 文/蒙蒙 一茂蚓、第九天 我趴在偏房一處隱蔽的房頂上張望丙笋。 院中可真熱鬧,春花似錦煌贴、人聲如沸御板。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)怠肋。三九已至,卻和暖如春淹朋,著一層夾襖步出監(jiān)牢的瞬間笙各,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工础芍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留杈抢,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,364評(píng)論 3 379
  • 正文 我出身青樓仑性,卻偏偏與公主長(zhǎng)得像惶楼,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子诊杆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,926評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • Promise對(duì)象的含義 所謂的Promise就是一個(gè)對(duì)象歼捐,用來(lái)傳遞異步操作的消息,它代表某個(gè)未來(lái)才會(huì)知道結(jié)果的事...
    萘小蒽閱讀 308評(píng)論 0 0
  • Promise 的含義 一句話概括一下promise的作用:可以將異步操作以同步操作的流程表達(dá)出來(lái)晨汹,避免了層層嵌套...
    雪萌萌萌閱讀 5,504評(píng)論 0 7
  • 編后吐槽:寫的快花眼豹储,很詳細(xì),耐心看必受益匪淺 JavaScript的執(zhí)行環(huán)境是「單線程」的淘这。所謂單線程剥扣,是指JS...
    果汁涼茶丶閱讀 4,637評(píng)論 8 27
  • Promiese 簡(jiǎn)單說就是一個(gè)容器巩剖,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果,語(yǔ)法上說钠怯,Pr...
    雨飛飛雨閱讀 3,361評(píng)論 0 19
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月球及,有人笑有人哭,有人歡樂有人憂愁呻疹,有人驚喜有人失落吃引,有的覺得收獲滿滿有...
    陌忘宇閱讀 8,547評(píng)論 28 53