Promise使用須知

一.關(guān)于Promise
promise 是異步編程的一種解決方案杯矩,比傳統(tǒng)的解決方案(回調(diào)函數(shù)和事件)更合理和更強大沽损。它由社區(qū)最早提出和實現(xiàn)亮元,ES6將其寫進了語言標準猛计,統(tǒng)一了用法,原生提供了Promise
對象爆捞。
所謂Promise
奉瘤,簡單說就是一個容器,里面保存著某個未來才會結(jié)束的事件(通常是一個異步操作)的結(jié)果。從語法上說盗温,Promise 是一個對象藕赞,從它可以獲取異步操作的消息。Promise 提供統(tǒng)一的 API卖局,各種異步操作都可以用同樣的方法進行處理斧蜕。
它代表一個異步操作。有三種狀態(tài):
pending
(進行中): 初始狀態(tài), 初始狀態(tài)砚偶,未完成或拒絕批销。
resolved
(已完成): 意味著操作成功完成。又名fulfilled染坯。
rejected
(已失敗): 意味著操作失敗风钻。

有了Promise
,就可以將異步操作以同步操作的流程表達出酒请,但它也有如下缺點
一旦創(chuàng)建它就會立即執(zhí)行骡技,無法中途取消。

如果不設(shè)置回調(diào)函數(shù)羞反,Promise
內(nèi)部拋出的錯誤布朦,不會反應(yīng)到外部。

當處于Pending
狀態(tài)時昼窗,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)是趴。

二.應(yīng)用示例

  1. 創(chuàng)建Promise
var promise = new Promise(

   /* executor */ 
   function(resolve, reject){
    ...
   }
);

? executor函數(shù)由Promise實現(xiàn)立即執(zhí)行,傳遞resolve和reject函數(shù). (在Promise構(gòu)造函數(shù)之前調(diào)用執(zhí)行器甚至返回創(chuàng)建的對象)
? 在 executor內(nèi)部澄惊,promise有如下的狀態(tài)變化可能:
? 1. resolve被調(diào)用唆途,promise由pending變?yōu)閞esolved,代表該Promise被成功解析(resolve)
? 2.reject被調(diào)用掸驱,promise由pending變?yōu)閞ejected肛搬,代表該Promise的值不能用于后續(xù)處理,即被拒絕了
注意:
如果在executor方法的執(zhí)行過程中拋出了任何異常毕贼,那么promise立即被拒絕(即相當于reject方法被調(diào)用)温赔,executor的返回值也就會被忽略。 如果一個promise對象處在resolved或rejected狀態(tài)而不是pending狀態(tài)鬼癣,那么它也可以被稱為settled狀態(tài)陶贼。

2.處理Promise實例
then:Promise實例生成以后,可以用then方法分別指定Resolved狀態(tài)和Reject狀態(tài)的回調(diào)函數(shù)待秃。

promise.then(function(value) {

 // success 狀態(tài)為Resolved時調(diào)用
}, function(error) { 
 // failure 狀態(tài)為Reject時調(diào)用
});

then方法可以接受兩個回調(diào)函數(shù)作為參數(shù)拜秧。
第一個回調(diào)函數(shù):在promise的狀態(tài)變成resolved時被調(diào)用。它的參數(shù)promise的resolve方法的返回值章郁。
第二個回調(diào)函數(shù):在promise的狀態(tài)變成rejected時被調(diào)用枉氮。它的參數(shù)promise的reject方法的返回值。且為可選參數(shù)。
catch:Promise.prototype.catch方法是.then(null, rejection)的別名嘲恍,用于指定發(fā)生錯誤時的回調(diào)函數(shù)

promise.then(function(posts) {

 // ...
}).catch(function(error) {
 console.log('發(fā)生錯誤雄驹!', error); // 處理 promise 和 前一個回調(diào)函數(shù)運行時發(fā)生的錯誤
});

擴展:
Promise.prototype.then
和 Promise.prototype.catch
方法返回 promises對象佃牛, 所以它們可以被鏈式調(diào)用。但此時返回的是以函數(shù)返回值生成的新的Promise實例医舆,不是原來那個Promise實例俘侠。[圖片上傳中。蔬将。爷速。(1)]

注意問題:
Promise 對象的錯誤具有“冒泡”性質(zhì),會一直向后傳遞霞怀,直到被捕獲為止惫东。也就是說,錯誤總是會被下一個catch語句捕獲毙石。

3.將多個Promise實例廉沮,包裝成一個新的Promise實例
**Promise.all(iterable)
** :當所有在可迭代參數(shù)中的 promises 已完成,或者第一個傳遞的 promise(指 reject)失敗時徐矩,返回 promise滞时。

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

當p1、p2和p3的狀態(tài)均為resolved時p的狀態(tài)為resolved滤灯。

當p1坪稽、p2或p3中的任意一個被rejected,p的狀態(tài)就變成rejected鳞骤,此時第一個被reject的實例的返回值窒百,會傳遞給p的回調(diào)函數(shù)。
具體的使用示例如下:
情形一:全部成功的情況

Promise.all([Promise.resolve('foo'),Promise.resolve('bar'),Promise.resolve('test')])

 .then(function(result){
           console.log(result); //結(jié)果為:[foo,bar,test]豫尽。即所有返回值的數(shù)組贝咙。

   })
   .catch(function(error) {
     console.log('error');   //不會被執(zhí)行
   });

情形二:全部失敗或部分失敗

Promise.all([Promise.resolve('foo'),Promise.reject('barError'),Promise.reject('testError')])

   .then(function(result){
           console.log(result);           //成功回調(diào) 不會被執(zhí)行

   })

   .catch(function(error) {
     console.log(error);   //結(jié)果為barError或testError。即第一個被reject的值拂募。

   });

三.常見的使用誤區(qū)
忘記添加 .catch()
通常情況庭猩,promise有如下兩種處理方式:

// ------------   不好的寫法   -------------

promise.then(function(data) {
   // success
 }, function(err) {   //僅處理promise運行時發(fā)生的錯誤。無法處理回調(diào)中的錯誤
   // error
 });
// ------------   好的寫法   ------------
promise.then(function(data) {
   // success
}).catch(function(err) {   // 處理 promise 和 前一個回調(diào)函數(shù)運行時發(fā)生的錯誤
   // error 
});

因為promise拋出的錯誤不會傳遞到外層代碼陈症。當使用沒有catch的第一種種寫法時蔼水,成功回調(diào)的錯誤將無法被處理。因此比較好的方式是录肯,總是使用catch方法趴腋。

在then或者catch函數(shù)中不使用return下面是在是用Promise時,一個很常見的錯誤寫法:

//------------   不好的寫法   ------------------

promise.then(function () {
  getUserInfo(userId);
}).then(function () {
 // 在這里可能希望在這個回調(diào)中使用用戶信息,但你可能會發(fā)現(xiàn)它根本不存在
});

會發(fā)生上面的錯誤优炬,是因為對Promise的返回及鏈式調(diào)用的理解不夠颁井。
每一個promise都會給你一個then()方法(或者catch,它們只是then(null,…)的語法糖)蠢护。這里我們是在then()方法的內(nèi)部來看:

promise.then(function () {

  return getUserInfo(userId);
}).then(function (userInfo) {
   HadleUser(userInfo);
}).catch(function(error) {
   console.log(error);
});

在回調(diào)中在有三種事可以做:
返回另一個promise
如果getUserInfo返回一個Promise雅宾,則HadleUser將在該promise變?yōu)閞esolved后執(zhí)行,并以該promise的返回作為入?yún)ⅰ?br> 返回一個同步值(或者undefined)
getUserInfo返回一個同步值葵硕,則改值會被包裝成一個resolved狀態(tài)的promise眉抬,HadleUser
將被立刻執(zhí)行,并以getUserInfo返回作為入?yún)ⅰ?br> 拋出一個同步錯誤懈凹。
getUserInfo返回一個同步錯誤蜀变,則該錯誤會被包裝成一個rejected狀態(tài)的promise,最終在catch中被捕獲介评。此時HadleUser將不會被執(zhí)行库北。
promises丟失
你認為下面的代碼會打印出什么?

Promise.resolve('foo').then(Promise.resolve('bar')).then(function (result) {
  console.log(result);
});

如果你認為打印出bar们陆,那你就大錯特錯了贤惯。它實際上會打印出foo。
原因是當你給then()傳遞一個非函數(shù)(比如一個promise)值的時候棒掠,它實際上會解釋為then(null)孵构,這會導(dǎo)致之前的promise的結(jié)果丟失。

四.最佳實踐總結(jié)

  • then方法中 永遠 return或 throw
  • 如果 promise鏈中可能出現(xiàn)錯誤烟很,一定添加 catch
  • 永遠傳遞函數(shù)給 then方法
  • 不要把 promise寫成嵌套

參考鏈接:
Promise -JavaScript | MDN
Promises 很酷颈墅,但很多人并沒有理解就在用了
Promise 對象

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市雾袱,隨后出現(xiàn)的幾起案子恤筛,更是在濱河造成了極大的恐慌,老刑警劉巖芹橡,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件毒坛,死亡現(xiàn)場離奇詭異,居然都是意外死亡林说,警方通過查閱死者的電腦和手機煎殷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來腿箩,“玉大人豪直,你說我怎么就攤上這事≈橐疲” “怎么了弓乙?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵末融,是天一觀的道長。 經(jīng)常有香客問我暇韧,道長勾习,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任懈玻,我火速辦了婚禮巧婶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘酪刀。我一直安慰自己,他們只是感情好钮孵,可當我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布骂倘。 她就那樣靜靜地躺著,像睡著了一般巴席。 火紅的嫁衣襯著肌膚如雪历涝。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天漾唉,我揣著相機與錄音荧库,去河邊找鬼。 笑死赵刑,一個胖子當著我的面吹牛分衫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播般此,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蚪战,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了铐懊?” 一聲冷哼從身側(cè)響起邀桑,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎科乎,沒想到半個月后壁畸,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡茅茂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年捏萍,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片空闲。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡照弥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出进副,到底是詐尸還是另有隱情这揣,我是刑警寧澤悔常,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站给赞,受9級特大地震影響机打,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜片迅,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一残邀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧柑蛇,春花似錦芥挣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至盆耽,卻和暖如春蹋砚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背摄杂。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工坝咐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人析恢。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓墨坚,卻偏偏與公主長得像,于是被迫代替她去往敵國和親映挂。 傳聞我的和親對象是個殘疾皇子框杜,可洞房花燭夜當晚...
    茶點故事閱讀 44,843評論 2 354

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,116評論 25 707
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)袖肥,斷路器咪辱,智...
    卡卡羅2017閱讀 134,656評論 18 139
  • 我就是想把老破電腦上下載的權(quán)利的游戲拉下來到ipad上看啊喂,該死的ipad各種不支持椎组,我又不想在裝itunes油狂,...
    marine0131閱讀 5,167評論 0 0
  • 商業(yè)模式:并非單純的盈利模式,包括成本分析寸癌、營收周期专筷、盈利模式幾個方面。閉環(huán)思維:從競品出發(fā)發(fā)現(xiàn)用戶痛點蒸苇,并提出解...
    生活鴿子閱讀 141評論 0 0
  • 今天磷蛹,2015年12月30日。一向愛刷微博的我溪烤,一如既往的 味咳,早晨起床先刷微博庇勃,關(guān)注熱搜娛樂程度高于任何熱點大事。...
    Karain_Wong閱讀 321評論 0 0