promise 簡介

一塌忽、什么是Promise

MDN對Promise的定義:Promise對象用于異步操作刃唐,它表示一個尚未完成且預(yù)計在未來完成的異步操作。Promise的出現(xiàn)解決了回調(diào)地獄的問題熟吏,使用Promise拐揭,我們可以利用then進(jìn)行鏈?zhǔn)交卣{(diào),將異步操作以同步操作的流程表示出來火脉。

二牵舵、Promise原理分析

Promise原理說起來并不難,它內(nèi)部有三個狀態(tài)倦挂,分別是pending畸颅,fulfilled和rejected 。
pending是對象創(chuàng)建后的初始狀態(tài)方援,當(dāng)對象fulfill(成功)時變?yōu)閒ulfilled没炒,當(dāng)對象reject(失敗)時變?yōu)閞ejected犯戏。且只能從pengding變?yōu)閒ulfilled或rejected 送火,而不能逆向或從fulfilled變?yōu)閞ejected 、從rejected變?yōu)閒ulfilled先匪。一旦狀態(tài)改變漾脂,就凝固了,會一直保持這個狀態(tài)胚鸯,不會再發(fā)生變化骨稿。當(dāng)狀態(tài)發(fā)生變化,promise.then綁定的函數(shù)就會被調(diào)用姜钳。
注意:Promise一旦新建就會「立即執(zhí)行」坦冠,無法取消。這也是它的缺點之一哥桥。

三 辙浑、Promise的基本用法

1、基本用法

//構(gòu)建Promise
var promise = new Promise(function (resolve, reject) {
    if (/* 異步操作成功 */) {
        resolve(data);
    } else {
        /* 異步操作失敗 */
        reject(error);
    }
});

promise.then(function(data) {
  // do something when success
}, function(error) {
  // do something when failure
});
  • 類似構(gòu)建對象拟糕,我們使用new來構(gòu)建一個Promise判呕。Promise接收一個函數(shù)作為參數(shù),該函數(shù)的兩個參數(shù)分別是resolve和reject送滞。這兩個函數(shù)就是就是回調(diào)函數(shù)侠草,由JavaScript引擎提供犁嗅。resolve函數(shù)的作用:在異步操作成功時調(diào)用边涕,并將異步操作的結(jié)果,作為參數(shù)傳遞出去; reject函數(shù)的作用:在異步操作失敗時調(diào)用式撼,并將異步操作報出的錯誤,作為參數(shù)傳遞出去。Promise實例生成以后荤牍,可以用then方法指定resolved狀態(tài)和reject狀態(tài)的回調(diào)函數(shù)案腺。
  • then方法會返回一個Promise。它有兩個參數(shù)康吵,分別為Promise從pending變?yōu)閒ulfilled和rejected時的回調(diào)函數(shù)(第二個參數(shù)非必選)劈榨。這兩個函數(shù)都接受Promise對象傳出的值作為參數(shù)。簡單來說晦嵌,then就是定義resolve和reject函數(shù)的同辣。
  • Promise新建后就會立即執(zhí)行。而then方法中指定的回調(diào)函數(shù)惭载,將在當(dāng)前腳本所有同步任務(wù)執(zhí)行完才會執(zhí)行旱函。如下例:
var promise = new Promise(function(resolve, reject) {
  console.log('before resolved');
  resolve();
  console.log('after resolved');
});

promise.then(function() {
  console.log('resolved');
});

console.log('outer');

-------output-------
before resolved
after resolved
outer
resolved

2、基本API

  • .then()
    對promise添加onFulfilled和onRejected回調(diào)描滔,并返回的是一個新的Promise實例(不是原來那個Promise實例)棒妨,且返回值將作為參數(shù)傳入這個新Promise的resolve函數(shù),可以使用鏈?zhǔn)綄懛êぁS捎谇耙粋€回調(diào)函數(shù)券腔,返回的還是一個Promise對象,這時后一個回調(diào)函數(shù)拘泞,就會等待該Promise對象的狀態(tài)發(fā)生變化纷纫,才會被調(diào)用。
  • .catch()
    該方法是.then(undefined, onRejected)的別名田弥,用于指定發(fā)生錯誤時的回調(diào)函數(shù)涛酗。
    promise對象的錯誤,會一直向后傳遞偷厦,直到被捕獲商叹。即錯誤總會被下一個catch所捕獲。then方法指定的回調(diào)函數(shù)只泼,若拋出錯誤剖笙,也會被下一個catch捕獲。catch中也能拋錯请唱,則需要后面的catch來捕獲弥咪。
  • .all()
    該方法用于將多個Promise實例,包裝成一個新的Promise實例十绑。
    Promise.all方法接受一個數(shù)組(或具有Iterator接口)作參數(shù)聚至,數(shù)組中的對象(p1、p2本橙、p3)均為promise實例(如果不是一個promise扳躬,該項會被用Promise.resolve轉(zhuǎn)換為一個promise)。它的狀態(tài)由這三個promise實例決定甚亭。當(dāng)p1, p2, p3狀態(tài)都變?yōu)閒ulfilled贷币,p的狀態(tài)才會變?yōu)閒ulfilled,并將三個promise返回的結(jié)果亏狰,按參數(shù)的順序(而不是 resolved的順序)存入數(shù)組役纹,傳給p的回調(diào)函數(shù)。當(dāng)p1, p2, p3其中之一狀態(tài)變?yōu)閞ejected暇唾,p的狀態(tài)也會變?yōu)閞ejected促脉,并把第一個被reject的promise的返回值,傳給p的回調(diào)函數(shù)策州。
var p1 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 3000, "first");
});
var p2 = new Promise(function (resolve, reject) {
    resolve('second');
});
var p3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 1000, "third");
}); 

Promise.all([p1, p2, p3]).then(function(values) { 
  console.log(values); 
});

-------output-------
//約 3s 后
["first", "second", "third"] 
var p1 = new Promise((resolve, reject) => { 
  setTimeout(resolve, 1000, "one"); 
}); 
var p2 = new Promise((resolve, reject) => { 
  setTimeout(reject, 2000, "two"); 
});
var p3 = new Promise((resolve, reject) => {
  reject("three");
});

Promise.all([p1, p2, p3]).then(function (value) {
    console.log('resolve', value);
}, function (error) {
    console.log('reject', error);    // => reject three
});

-------output-------
reject three
  • .race()
    Promise.race方法同樣接受一個數(shù)組(或具有Iterator接口)作參數(shù)嘲叔。當(dāng)p1, p2, p3中有一個實例的狀態(tài)發(fā)生改變(變?yōu)閒ulfilled或rejected),p的狀態(tài)就跟著改變抽活。并把第一個改變狀態(tài)的promise的返回值硫戈,傳給p的回調(diào)函數(shù)。
/* 例3.11 */
var p1 = new Promise(function(resolve, reject) { 
    setTimeout(reject, 500, "one"); 
});
var p2 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 100, "two"); 
});

Promise.race([p1, p2]).then(function(value) {
    console.log('resolve', value); 
}, function(error) {
    //not called
    console.log('reject', error); 
});
-------output-------
resolve two

var p3 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 500, "three");
});
var p4 = new Promise(function(resolve, reject) { 
    setTimeout(reject, 100, "four"); 
});

Promise.race([p3, p4]).then(function(value) {
    //not called
    console.log('resolve', value);              
}, function(error) {
    console.log('reject', error); 
});
-------output-------
reject four
  • .resolve()
    它可以看做new Promise()的快捷方式下硕。
Promise.resolve('Success');

/*******等同于*******/
new Promise(function (resolve) {
    resolve('Success');
});

這段代碼會讓這個Promise對象立即進(jìn)入resolved狀態(tài)丁逝,并將結(jié)果success傳遞給then指定的onFulfilled回調(diào)函數(shù)。由于Promise.resolve()也是返回Promise對象梭姓,因此可以用.then()處理其返回值霜幼。

/* 例3.13 */
Promise.resolve('success').then(function (value) {
    console.log(value);
});
-------output-------
Success
  • .reject()
    這個方法和上述的Promise.resolve()類似,它也是new Promise()的快捷方式誉尖。
Promise.reject(new Error('error'));

/*******等同于*******/
new Promise(function (resolve, reject) {
    reject(new Error('error'));
});

這段代碼會讓這個Promise對象立即進(jìn)入rejected狀態(tài)罪既,并將錯誤對象傳遞給then指定的onRejected回調(diào)函數(shù)。

四 Promise常見問題

1、reject 和 catch 的區(qū)別

  • promise.then(onFulfilled, onRejected)在onFulfilled中發(fā)生異常的話琢感,在onRejected中是捕獲不到這個異常的丢间。
  • promise.then(onFulfilled).catch(onRejected).then中產(chǎn)生的異常能在.catch中捕獲一般情況,還是建議使用第二種驹针,因為能捕獲之前的所有異常烘挫。當(dāng)然了,第二種的.catch()也可以使用.then()表示柬甥,它們本質(zhì)上是沒有區(qū)別的饮六,.catch === .then(null, onRejected)
    2、promise狀態(tài)變?yōu)閞esove或reject苛蒲,就凝固了卤橄,不會再改變
console.log(1);
new Promise(function (resolve, reject){
    reject();
    setTimeout(function (){
        resolve();            //not called
    }, 0);
}).then(function(){
    console.log(2);
}, function(){
    console.log(3);
});
console.log(4);

-------output-------
1
4
3

3、在異步回調(diào)中拋錯臂外,不會被catch到

// Errors thrown inside asynchronous functions will act like uncaught errors
var promise = new Promise(function(resolve, reject) {
  setTimeout(function() {
    throw 'Uncaught Exception!';
  }, 1000);
});

promise.catch(function(e) {
  console.log(e);       //This is never called
});
?著作權(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
  • 文/潘曉璐 我一進(jìn)店門忱辅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人谭溉,你說我怎么就攤上這事墙懂。” “怎么了扮念?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵损搬,是天一觀的道長。 經(jīng)常有香客問我柜与,道長巧勤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任弄匕,我火速辦了婚禮颅悉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘迁匠。我一直安慰自己剩瓶,他們只是感情好驹溃,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著延曙,像睡著了一般豌鹤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上搂鲫,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天傍药,我揣著相機與錄音磺平,去河邊找鬼魂仍。 笑死,一個胖子當(dāng)著我的面吹牛拣挪,可吹牛的內(nèi)容都是我干的擦酌。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼菠劝,長吁一口氣:“原來是場噩夢啊……” “哼赊舶!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起赶诊,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤笼平,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后舔痪,有當(dāng)?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
  • 正文 我出身青樓和泌,卻偏偏與公主長得像村缸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子武氓,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354