Promise 對象

  1. Promise 的含義
  2. 基本用法
  3. Promise.prototype.then()
  4. Promise.prototype.catch()
  5. Promise.prototype.finally()
  6. Promise.all()
  7. Promise.race()
  8. Promise.resolve()
  9. Promise.reject()
  10. 應用
  11. Promise.try()

1 Promise 的含義 § ?

Promise 是異步編程的一種解決方案关霸,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強大缸逃。它由社區(qū)最早提出和實現(xiàn),ES6 將其寫進了語言標準辅愿,統(tǒng)一了用法豆瘫,原生提供了Promise對象。

所謂Promise踪少,簡單說就是一個容器批什,里面保存著某個未來才會結束的事件(通常是一個異步操作)的結果哆窿。從語法上說链烈,Promise 是一個對象,從它可以獲取異步操作的消息挚躯。Promise 提供統(tǒng)一的 API强衡,各種異步操作都可以用同樣的方法進行處理。

Promise對象有以下兩個特點码荔。

(1)對象的狀態(tài)不受外界影響漩勤。Promise對象代表一個異步操作,有三種狀態(tài):pending(進行中)缩搅、fulfilled(已成功)和rejected(已失斣桨堋)。只有異步操作的結果硼瓣,可以決定當前是哪一種狀態(tài)究飞,任何其他操作都無法改變這個狀態(tài)置谦。這也是Promise這個名字的由來,它的英語意思就是“承諾”亿傅,表示其他手段無法改變媒峡。

(2)一旦狀態(tài)改變,就不會再變葵擎,任何時候都可以得到這個結果谅阿。Promise對象的狀態(tài)改變,只有兩種可能:從pending變?yōu)閒ulfilled和從pending變?yōu)閞ejected酬滤。只要這兩種情況發(fā)生签餐,狀態(tài)就凝固了,不會再變了盯串,會一直保持這個結果氯檐,這時就稱為 resolved(已定型)。如果改變已經(jīng)發(fā)生了嘴脾,你再對Promise對象添加回調(diào)函數(shù),也會立即得到這個結果蔬墩。這與事件(Event)完全不同译打,事件的特點是,如果你錯過了它拇颅,再去監(jiān)聽奏司,是得不到結果的。

注意樟插,為了行文方便韵洋,本章后面的resolved統(tǒng)一只指fulfilled狀態(tài),不包含rejected狀態(tài)黄锤。

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

Promise也有一些缺點痹届。首先,無法取消Promise打月,一旦新建它就會立即執(zhí)行队腐,無法中途取消。其次奏篙,如果不設置回調(diào)函數(shù)柴淘,Promise內(nèi)部拋出的錯誤,不會反應到外部。第三悠就,當處于pending狀態(tài)時千绪,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)。

如果某些事件不斷地反復發(fā)生梗脾,一般來說荸型,使用 Stream 模式是比部署Promise更好的選擇。

2 基本用法 § ?

ES6 規(guī)定炸茧,Promise對象是一個構造函數(shù)瑞妇,用來生成Promise實例。

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 異步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

Promise構造函數(shù)接受一個函數(shù)作為參數(shù)梭冠,該函數(shù)的兩個參數(shù)分別是resolve和reject辕狰。它們是兩個函數(shù),由 JavaScript 引擎提供控漠,不用自己部署蔓倍。

Promise實例生成以后,可以用then方法分別指定resolved狀態(tài)和rejected狀態(tài)的回調(diào)函數(shù)盐捷。

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

3 Promise.prototype.then() § ?

Promise 實例具有then方法偶翅,也就是說,then方法是定義在原型對象Promise.prototype上的碉渡。它的作用是為 Promise 實例添加狀態(tài)改變時的回調(diào)函數(shù)聚谁。前面說過,then方法的第一個參數(shù)是resolved狀態(tài)的回調(diào)函數(shù)滞诺,第二個參數(shù)(可選)是rejected狀態(tài)的回調(diào)函數(shù)形导。

then方法返回的是一個新的Promise實例(注意,不是原來那個Promise實例)习霹。因此可以采用鏈式寫法朵耕,即then方法后面再調(diào)用另一個then方法。

4 Promise.prototype.catch() § ?

Promise.prototype.catch方法是.then(null, rejection)的別名淋叶,用于指定發(fā)生錯誤時的回調(diào)函數(shù)憔披。

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

Promise 對象的錯誤具有“冒泡”性質(zhì)爸吮,會一直向后傳遞芬膝,直到被捕獲為止。也就是說形娇,錯誤總是會被下一個catch語句捕獲锰霜。

getJSON('/post/1.json').then(function(post) {
  return getJSON(post.commentURL);
}).then(function(comments) {
  // some code
}).catch(function(error) {
  // 處理前面三個Promise產(chǎn)生的錯誤
});

上面代碼中,一共有三個 Promise 對象:一個由getJSON產(chǎn)生桐早,兩個由then產(chǎn)生癣缅。它們之中任何一個拋出的錯誤厨剪,都會被最后一個catch捕獲。

5 Promise.prototype.finally() § ?

finally方法用于指定不管 Promise 對象最后狀態(tài)如何友存,都會執(zhí)行的操作祷膳。該方法是 ES2018 引入標準的。

6 Promise.all() § ?

Promise.all方法用于將多個 Promise 實例屡立,包裝成一個新的 Promise 實例直晨。

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

上面代碼中,Promise.all方法接受一個數(shù)組作為參數(shù)膨俐,p1勇皇、p2、p3都是 Promise 實例焚刺,如果不是敛摘,就會先調(diào)用下面講到的Promise.resolve方法,將參數(shù)轉(zhuǎn)為 Promise 實例乳愉,再進一步處理兄淫。(Promise.all方法的參數(shù)可以不是數(shù)組,但必須具有 Iterator 接口蔓姚,且返回的每個成員都是 Promise 實例捕虽。)

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

(1)只有p1挨措、p2、p3的狀態(tài)都變成fulfilled崩溪,p的狀態(tài)才會變成fulfilled浅役,此時p1、p2伶唯、p3的返回值組成一個數(shù)組觉既,傳遞給p的回調(diào)函數(shù)。

(2)只要p1乳幸、p2瞪讼、p3之中有一個被rejected,p的狀態(tài)就變成rejected粹断,此時第一個被reject的實例的返回值符欠,會傳遞給p的回調(diào)函數(shù)。

7 Promise.race() § ?

Promise.race方法同樣是將多個 Promise 實例瓶埋,包裝成一個新的 Promise 實例希柿。

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

上面代碼中诊沪,只要p1、p2曾撤、p3之中有一個實例率先改變狀態(tài)端姚,p的狀態(tài)就跟著改變。那個率先改變的 Promise 實例的返回值挤悉,就傳遞給p的回調(diào)函數(shù)渐裸。

8 Promise.resolve() § ?

有時需要將現(xiàn)有對象轉(zhuǎn)為 Promise 對象,Promise.resolve方法就起到這個作用尖啡。

const jsPromise = Promise.resolve($.ajax('/whatever.json'));

上面代碼將 jQuery 生成的deferred對象橄仆,轉(zhuǎn)為一個新的 Promise 對象。

Promise.resolve等價于下面的寫法衅斩。

Promise.resolve('foo')
// 等價于
new Promise(resolve => resolve('foo'))

Promise.resolve方法的參數(shù)分成四種情況盆顾。

(1)參數(shù)是一個 Promise 實例

如果參數(shù)是 Promise 實例,那么Promise.resolve將不做任何修改畏梆、原封不動地返回這個實例您宪。

(2)參數(shù)是一個thenable對象

thenable對象指的是具有then方法的對象,比如下面這個對象奠涌。

let thenable = {
  then: function(resolve, reject) {
    resolve(42);
  }
};

Promise.resolve方法會將這個對象轉(zhuǎn)為 Promise 對象宪巨,然后就立即執(zhí)行thenable對象的then方法。

let thenable = {
  then: function(resolve, reject) {
    resolve(42);
  }
};

let p1 = Promise.resolve(thenable);
p1.then(function(value) {
  console.log(value);  // 42
});

上面代碼中溜畅,thenable對象的then方法執(zhí)行后捏卓,對象p1的狀態(tài)就變?yōu)閞esolved,從而立即執(zhí)行最后那個then方法指定的回調(diào)函數(shù)慈格,輸出 42怠晴。

(3)參數(shù)不是具有then方法的對象,或根本就不是對象

如果參數(shù)是一個原始值浴捆,或者是一個不具有then方法的對象蒜田,則Promise.resolve方法返回一個新的 Promise 對象,狀態(tài)為resolved选泻。

const p = Promise.resolve('Hello');

p.then(function (s){
  console.log(s)
});
// Hello

上面代碼生成一個新的 Promise 對象的實例p冲粤。由于字符串Hello不屬于異步操作(判斷方法是字符串對象不具有 then 方法),返回 Promise 實例的狀態(tài)從一生成就是resolved页眯,所以回調(diào)函數(shù)會立即執(zhí)行梯捕。Promise.resolve方法的參數(shù),會同時傳給回調(diào)函數(shù)窝撵。

(4)不帶有任何參數(shù)

Promise.resolve方法允許調(diào)用時不帶參數(shù)傀顾,直接返回一個resolved狀態(tài)的 Promise 對象。

所以忿族,如果希望得到一個 Promise 對象锣笨,比較方便的方法就是直接調(diào)用Promise.resolve方法蝌矛。

const p = Promise.resolve();

p.then(function () {
  // ...
});

上面代碼的變量p就是一個 Promise 對象。

需要注意的是错英,立即resolve的 Promise 對象入撒,是在本輪“事件循環(huán)”(event loop)的結束時,而不是在下一輪“事件循環(huán)”的開始時椭岩。

9 Promise.reject() § ?

Promise.reject(reason)方法也會返回一個新的 Promise 實例茅逮,該實例的狀態(tài)為rejected。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末判哥,一起剝皮案震驚了整個濱河市献雅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌塌计,老刑警劉巖挺身,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異锌仅,居然都是意外死亡章钾,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門热芹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來贱傀,“玉大人,你說我怎么就攤上這事伊脓「” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵报腔,是天一觀的道長株搔。 經(jīng)常有香客問我,道長榄笙,這世上最難降的妖魔是什么邪狞? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任祷蝌,我火速辦了婚禮茅撞,結果婚禮上,老公的妹妹穿的比我還像新娘巨朦。我一直安慰自己米丘,他們只是感情好,可當我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布糊啡。 她就那樣靜靜地躺著拄查,像睡著了一般。 火紅的嫁衣襯著肌膚如雪棚蓄。 梳的紋絲不亂的頭發(fā)上堕扶,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天碍脏,我揣著相機與錄音,去河邊找鬼稍算。 笑死典尾,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的糊探。 我是一名探鬼主播钾埂,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼科平!你這毒婦竟也來了褥紫?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤瞪慧,失蹤者是張志新(化名)和其女友劉穎髓考,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體弃酌,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡绳军,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了矢腻。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片门驾。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖多柑,靈堂內(nèi)的尸體忽然破棺而出奶是,到底是詐尸還是另有隱情,我是刑警寧澤竣灌,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布聂沙,位于F島的核電站,受9級特大地震影響初嘹,放射性物質(zhì)發(fā)生泄漏及汉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一屯烦、第九天 我趴在偏房一處隱蔽的房頂上張望坷随。 院中可真熱鬧,春花似錦驻龟、人聲如沸温眉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽类溢。三九已至,卻和暖如春露懒,著一層夾襖步出監(jiān)牢的瞬間闯冷,已是汗流浹背砂心。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蛇耀,地道東北人计贰。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像蒂窒,于是被迫代替她去往敵國和親躁倒。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,060評論 2 355

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

  • Promise 對象 Promise 的含義 Promise 是異步編程的一種解決方案洒琢,比傳統(tǒng)的解決方案——回調(diào)函...
    neromous閱讀 8,707評論 1 56
  • Promise對象是一種解決異步問題的方法秧秉,還有的解決方案是asyns 和 await (es7) 這么是目前的終...
    站在大神的肩膀上看世界閱讀 1,265評論 0 6
  • 一、Promise的含義 Promise在JavaScript語言中早有實現(xiàn)衰抑,ES6將其寫進了語言標準象迎,統(tǒng)一了用法...
    Alex灌湯貓閱讀 826評論 0 2
  • 目錄:Promise 的含義基本用法Promise.prototype.then()Promise.prototy...
    BluesCurry閱讀 1,494評論 0 8
  • 周天下午,兒子吵著要跟我一起送姐姐上學呛踊。 在上學的路上砾淌,姐弟倆一路繞口令,一會兒是黑化肥谭网,一會兒又是灰化肥汪厨,一會兒...
    立邦柒閱讀 946評論 8 7