promise對象

1.什么是Promise

Promise 是異步編程的一種解決方案郑口,其實是一個構(gòu)造函數(shù),自己身上有all各淀、reject懒鉴、resolve這幾個方法,原型上有then碎浇、catch等方法临谱。

Promise對象有以下兩個特點:

1)對象的狀態(tài)不受外界影響。Promise對象代表一個異步操作奴璃,有三種狀態(tài):pending(進(jìn)行中)悉默、fulfilled(已成功)和rejected(已失敗)苟穆。只有異步操作的結(jié)果抄课,可以決定當(dāng)前是哪一種狀態(tài),任何其他操作都無法改變這個狀態(tài)雳旅。這也是Promise這個名字的由來跟磨,它的英語意思就是“承諾”,表示其他手段無法改變攒盈。

2)一旦狀態(tài)改變抵拘,就不會再變,任何時候都可以得到這個結(jié)果型豁。Promise對象的狀態(tài)改變僵蛛,只有兩種可能:從pending變?yōu)閒ulfilled和從pending變?yōu)閞ejected。只要這兩種情況發(fā)生迎变,狀態(tài)就凝固了充尉,不會再變了,會一直保持這個結(jié)果氏豌,這時就稱為 resolved(已定型)喉酌。如果改變已經(jīng)發(fā)生了,你再對Promise對象添加回調(diào)函數(shù)泵喘,也會立即得到這個結(jié)果。這與事件(Event)完全不同般妙,事件的特點是纪铺,如果你錯過了它,再去監(jiān)聽碟渺,是得不到結(jié)果的鲜锚。

下面先 new一個Promise

let p = new Promise(function(resolve, reject){

??? //做一些異步操作

??? setTimeout(function(){

??????? console.log('執(zhí)行完成Promise');

??????? resolve('要返回的數(shù)據(jù)可以任何數(shù)據(jù)例如接口返回數(shù)據(jù)');

???? }, 2000);

});

刷新頁面會發(fā)現(xiàn)控制臺直接打出

其執(zhí)行過程是:執(zhí)行了一個異步操作,也就是setTimeout,2秒后芜繁,輸出“執(zhí)行完成”旺隙,并且調(diào)用resolve方法。

注意骏令!我只是new了一個對象蔬捷,并沒有調(diào)用它,我們傳進(jìn)去的函數(shù)就已經(jīng)執(zhí)行了榔袋,這是需要注意的一個細(xì)節(jié)周拐。所以我們用Promise的時候一般是包在一個函數(shù)中,在需要的時候去運行這個函數(shù)凰兑,如

<div onClick={promiseClick}>開始異步請求</div>

const promiseClick =()=>{

??? console.log('點擊方法被調(diào)用')

??? let p = new Promise(function(resolve, reject){

??????? //做一些異步操作

??????? setTimeout(function(){

???????????? console.log('執(zhí)行完成Promise');

???????????? resolve('要返回的數(shù)據(jù)可以任何數(shù)據(jù)例如接口返回數(shù)據(jù)');

??????? }, 2000);

?? });

? ? ? ? return p

}

刷新頁面的時候是沒有任何反映的妥粟,但是點擊后控制臺打出

當(dāng)放在函數(shù)里面的時候只有調(diào)用的時候才會被執(zhí)行

那么,接下里解決兩個問題:

1吏够、為什么要放在函數(shù)里面

2勾给、resolve是個什么鬼

我們包裝好的函數(shù)最后,會return出Promise對象锅知,也就是說播急,執(zhí)行這個函數(shù)我們得到了一個Promise對象。接下來就可以用Promise對象上有then喉镰、catch方法了旅择,這就是Promise的強大之處了,看下面的代碼:

promiseClick().then(function(data){

??? console.log(data);

??? //后面可以用傳過來的數(shù)據(jù)做些其他操作

});

這樣控制臺輸出

先是方法被調(diào)用起床執(zhí)行了promise,最后執(zhí)行了promise的then方法侣姆,then方法是一個函數(shù)接受一個參數(shù)是接受resolve返回的數(shù)據(jù)這事就輸出了‘要返回的數(shù)據(jù)可以任何數(shù)據(jù)例如接口返回數(shù)據(jù)’

這時候你應(yīng)該有所領(lǐng)悟了生真,原來then里面的函數(shù)就跟我們平時的回調(diào)函數(shù)一個意思,能夠在promiseClick這個異步任務(wù)執(zhí)行完成之后被執(zhí)行捺宗。這就是Promise的作用了柱蟀,簡單來講,就是能把原來的回調(diào)寫法分離出來蚜厉,在異步操作執(zhí)行完后长已,用鏈?zhǔn)秸{(diào)用的方式執(zhí)行回調(diào)函數(shù)。

你可能會覺得在這個和寫一個回調(diào)函數(shù)沒有什么區(qū)別昼牛;那么术瓮,如果有多層回調(diào)該怎么辦?如果callback也是一個異步操作贰健,而且執(zhí)行完后也需要有相應(yīng)的回調(diào)函數(shù)胞四,該怎么辦呢?總不能再定義一個callback2伶椿,然后給callback傳進(jìn)去吧辜伟。而Promise的優(yōu)勢在于氓侧,可以在then方法中繼續(xù)寫Promise對象并返回,然后繼續(xù)調(diào)用then來進(jìn)行回調(diào)操作导狡。

所以:精髓在于:Promise只是能夠簡化層層回調(diào)的寫法约巷,而實質(zhì)上,Promise的精髓是“狀態(tài)”旱捧,用維護(hù)狀態(tài)独郎、傳遞狀態(tài)的方式來使得回調(diào)函數(shù)能夠及時調(diào)用,它比傳遞callback函數(shù)要簡單廊佩、靈活的多囚聚。所以使用Promise的正確場景是這樣的:

promiseClick()

.then(function(data){

? ? console.log(data);

? ? return runAsync2();

})

.then(function(data){

? ? console.log(data);

? ? return runAsync3();

})

.then(function(data){

? ? console.log(data);

})

這樣能夠按順序,每隔兩秒輸出每個異步回調(diào)中的內(nèi)容标锄,在runAsync2中傳給resolve的數(shù)據(jù)顽铸,能在接下來的then方法中拿到。

reject的用法

以上是對promise的resolve用法進(jìn)行了解釋料皇,相當(dāng)于resolve是對promise成功時候的回調(diào)谓松,它把promise的狀態(tài)修改為

fullfiled,那么践剂,reject就是失敗的時候的回調(diào)鬼譬,他把promise的狀態(tài)修改為rejected,這樣我們在then中就能捕捉到逊脯,然后執(zhí)行“失敗”情況的回調(diào)优质。

functionpromiseClick(){

let p = new Promise(function(resolve, reject){

setTimeout(function(){

var num = Math.ceil(Math.random()*20); //生成1-10的隨機數(shù)

console.log('隨機數(shù)生成的值:',num)

if(num<=10){

resolve(num);

}

else{

reject('數(shù)字太于10了即將執(zhí)行失敗回調(diào)');

}

}, 2000);

? })

? return p

? }

promiseClick().then(

function(data){

console.log('resolved成功回調(diào)');

console.log('成功回調(diào)接受的值:',data);

},

function(reason, data){

console.log('rejected失敗回調(diào)');

console.log('失敗執(zhí)行回調(diào)拋出失敗原因:',reason);

}

);

執(zhí)行結(jié)果:

以上代碼:調(diào)用promiseClick方法執(zhí)行,2秒后獲取到一個隨機數(shù)军洼,如果小于10巩螃,我們算成功,調(diào)用resolve修改Promise的狀態(tài)為fullfiled匕争。否則我們認(rèn)為是“失敗”了避乏,調(diào)用reject并傳遞一個參數(shù),作為失敗的原因甘桑。并將狀態(tài)改成rejected

運行promiseClick并且在then中傳了兩個參數(shù)拍皮,這兩個參數(shù)分別是兩個函數(shù),then方法可以接受兩個參數(shù)跑杭,第一個對應(yīng)resolve的回調(diào)铆帽,第二個對應(yīng)reject的回調(diào)。(也就是說then方法中接受兩個回調(diào)德谅,一個成功的回調(diào)函數(shù)锄贼,一個失敗的回調(diào)函數(shù),并且能在回調(diào)函數(shù)中拿到成功的數(shù)據(jù)和失敗的原因)女阀,所以我們能夠分別拿到成功和失敗傳過來的數(shù)據(jù)就有以上的運行結(jié)果
catch的用法

與Promise對象方法then方法并行的一個方法就是catch,與try? catch類似宅荤,catch就是用來捕獲異常的,也就是和then方法中接受的第二參數(shù)rejected的回調(diào)是一樣的浸策,如下:

function promiseClick(){

let p = new Promise(function(resolve, reject){

setTimeout(function(){

var num = Math.ceil(Math.random()*20); //生成1-10的隨機數(shù)

console.log('隨機數(shù)生成的值:',num)

if(num<=10){

resolve(num);

}

else{

reject('數(shù)字太于10了即將執(zhí)行失敗回調(diào)');

}

}, 2000);

? })

? return p

? }

promiseClick().then(

function(data){

console.log('resolved成功回調(diào)');

console.log('成功回調(diào)接受的值:',data);

}

)

.catch(function(reason, data){

console.log('catch到rejected失敗回調(diào)');

console.log('catch失敗執(zhí)行回調(diào)拋出失敗原因:',reason);

})

執(zhí)行結(jié)果:

效果和寫在then的第二個參數(shù)里面一樣冯键。它將大于10的情況下的失敗回調(diào)的原因輸出,但是庸汗,它還有另外一個作用:在執(zhí)行resolve的回調(diào)(也就是上面then中的第一個參數(shù))時惫确,如果拋出異常了(代碼出錯了),那么并不會報錯卡死js蚯舱,而是會進(jìn)到這個catch方法中改化。如下:

function promiseClick(){

let p = new Promise(function(resolve, reject){

setTimeout(function(){

var num = Math.ceil(Math.random()*20); //生成1-10的隨機數(shù)

console.log('隨機數(shù)生成的值:',num)

if(num<=10){

resolve(num);

}

else{

reject('數(shù)字太于10了即將執(zhí)行失敗回調(diào)');

}

}, 2000);

? })

? return p

? }

promiseClick().then(

function(data){

console.log('resolved成功回調(diào)');

console.log('成功回調(diào)接受的值:',data);

console.log(noData);

}

)

.catch(function(reason, data){

console.log('catch到rejected失敗回調(diào)');

console.log('catch失敗執(zhí)行回調(diào)拋出失敗原因:',reason);

});


執(zhí)行結(jié)果:

在resolve的回調(diào)中,我們console.log(noData);而noData這個變量是沒有被定義的枉昏。如果我們不用Promise陈肛,代碼運行到這里就直接在控制臺報錯了,不往下運行了兄裂。但是在這里句旱,會得到上圖的結(jié)果,也就是說進(jìn)到catch方法里面去了晰奖,而且把錯誤原因傳到了reason參數(shù)中谈撒。即便是有錯誤的代碼也不會報錯了

all的用法

與then同級的另一個方法,all方法匾南,該方法提供了并行執(zhí)行異步操作的能力啃匿,并且在所有異步操作執(zhí)行完后并且執(zhí)行結(jié)果都是成功的時候才執(zhí)行回調(diào)。

將上述方法復(fù)制兩份并重命名promiseClick3(), promiseClick2(), promiseClick1()蛆楞,如下

function promiseClick1(){

let p = new Promise(function(resolve, reject){

setTimeout(function(){

var num = Math.ceil(Math.random()*20); //生成1-10的隨機數(shù)

console.log('隨機數(shù)生成的值:',num)

if(num<=10){

resolve(num);

}

else{

reject('數(shù)字太于10了即將執(zhí)行失敗回調(diào)');

}

}, 2000);

? })

? return p

? }

? function promiseClick2(){

let p = new Promise(function(resolve, reject){

setTimeout(function(){

var num = Math.ceil(Math.random()*20); //生成1-10的隨機數(shù)

console.log('隨機數(shù)生成的值:',num)

if(num<=10){

resolve(num);

}

else{

reject('數(shù)字太于10了即將執(zhí)行失敗回調(diào)');

}

}, 2000);

? })

? return p

? }

? function promiseClick3(){

let p = new Promise(function(resolve, reject){

setTimeout(function(){

var num = Math.ceil(Math.random()*20); //生成1-10的隨機數(shù)

console.log('隨機數(shù)生成的值:',num)

if(num<=10){

resolve(num);

}

else{

reject('數(shù)字太于10了即將執(zhí)行失敗回調(diào)');

}

}, 2000);

? })

? return p

? }

Promise

.all([promiseClick3(), promiseClick2(), promiseClick1()])

.then(function(results){

console.log(results);

})

Promise.all來執(zhí)行溯乒,all接收一個數(shù)組參數(shù),這組參數(shù)為需要執(zhí)行異步操作的所有方法臊岸,里面的值最終都算返回Promise對象橙数。這樣,三個異步操作的并行執(zhí)行的帅戒,等到它們都執(zhí)行完后才會進(jìn)到then里面灯帮。那么,三個異步操作返回的數(shù)據(jù)哪里去了呢逻住?都在then里面钟哥,all會把所有異步操作的結(jié)果放進(jìn)一個數(shù)組中傳給then,然后再執(zhí)行then方法的成功回調(diào)將結(jié)果接收瞎访,結(jié)果如下:(分別執(zhí)行得到結(jié)果腻贰,all統(tǒng)一執(zhí)行完三個函數(shù)并將值存在一個數(shù)組里面返回給then進(jìn)行回調(diào)輸出):

這樣以后就可以用all并行執(zhí)行多個異步操作,并且在一個回調(diào)中處理所有的返回數(shù)據(jù)扒秸,比如你需要提前準(zhǔn)備好所有數(shù)據(jù)才渲染頁面的時候就可以使用all,執(zhí)行多個異步操作將所有的數(shù)據(jù)處理好播演,再去渲染

race的用法

all是等所有的異步操作都執(zhí)行完了再執(zhí)行then方法冀瓦,那么race方法就是相反的,誰先執(zhí)行完成就先執(zhí)行回調(diào)写烤。

我們將上面的方法延遲分別改成2,3,4秒

function promiseClick1(){

let p = new Promise(function(resolve, reject){

setTimeout(function(){

var num = Math.ceil(Math.random()*20); //生成1-10的隨機數(shù)

console.log('2s隨機數(shù)生成的值:',num)

if(num<=10){

resolve(num);

}

else{

reject('2s數(shù)字太于10了即將執(zhí)行失敗回調(diào)');

}

}, 2000);

? })

? return p

? }

? function promiseClick2(){

let p = new Promise(function(resolve, reject){

setTimeout(function(){

var num = Math.ceil(Math.random()*20); //生成1-10的隨機數(shù)

console.log('3s隨機數(shù)生成的值:',num)

if(num<=10){

resolve(num);

}

else{

reject('3s數(shù)字太于10了即將執(zhí)行失敗回調(diào)');

}

}, 3000);

? })

? return p

? }

? function promiseClick3(){

let p = new Promise(function(resolve, reject){

setTimeout(function(){

var num = Math.ceil(Math.random()*20); //生成1-10的隨機數(shù)

console.log('4s隨機數(shù)生成的值:',num)

if(num<=10){

resolve(num);

}

else{

reject('4s數(shù)字太于10了即將執(zhí)行失敗回調(diào)');

}

}, 4000);

? })

? return p

? }

Promise

.race([promiseClick3(), promiseClick2(), promiseClick1()])

.then(function(results){

console.log(results);

},function(reason){

console.log(reason);

});

當(dāng)2s后promiseClick1執(zhí)行完成后就已經(jīng)進(jìn)入到了then里面回調(diào)翼闽,在then里面的回調(diào)開始執(zhí)行時,promiseClick2()和promiseClick3()并沒有停止洲炊,仍舊再執(zhí)行感局。于是再過3秒后,輸出了他們各自的回調(diào)值


race的使用比如可以使用在一個請求在10s內(nèi)請求成功的話就走then方法暂衡,如果10s內(nèi)沒有請求成功的話進(jìn)入reject回調(diào)執(zhí)行另一個操作询微。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市狂巢,隨后出現(xiàn)的幾起案子撑毛,更是在濱河造成了極大的恐慌,老刑警劉巖隧膘,帶你破解...
    沈念sama閱讀 221,888評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件代态,死亡現(xiàn)場離奇詭異,居然都是意外死亡疹吃,警方通過查閱死者的電腦和手機蹦疑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來萨驶,“玉大人歉摧,你說我怎么就攤上這事∏晃兀” “怎么了叁温?”我有些...
    開封第一講書人閱讀 168,386評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長核畴。 經(jīng)常有香客問我膝但,道長,這世上最難降的妖魔是什么谤草? 我笑而不...
    開封第一講書人閱讀 59,726評論 1 297
  • 正文 為了忘掉前任跟束,我火速辦了婚禮,結(jié)果婚禮上丑孩,老公的妹妹穿的比我還像新娘冀宴。我一直安慰自己紊服,他們只是感情好讨彼,可當(dāng)我...
    茶點故事閱讀 68,729評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著茫陆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪逃延。 梳的紋絲不亂的頭發(fā)上览妖,一...
    開封第一講書人閱讀 52,337評論 1 310
  • 那天,我揣著相機與錄音真友,去河邊找鬼黄痪。 笑死,一個胖子當(dāng)著我的面吹牛盔然,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播是嗜,決...
    沈念sama閱讀 40,902評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼愈案,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了鹅搪?” 一聲冷哼從身側(cè)響起站绪,我...
    開封第一講書人閱讀 39,807評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎丽柿,沒想到半個月后恢准,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,349評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡甫题,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,439評論 3 340
  • 正文 我和宋清朗相戀三年馁筐,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坠非。...
    茶點故事閱讀 40,567評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡敏沉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出炎码,到底是詐尸還是另有隱情盟迟,我是刑警寧澤,帶...
    沈念sama閱讀 36,242評論 5 350
  • 正文 年R本政府宣布潦闲,位于F島的核電站攒菠,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏歉闰。R本人自食惡果不足惜辖众,卻給世界環(huán)境...
    茶點故事閱讀 41,933評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望新娜。 院中可真熱鬧赵辕,春花似錦、人聲如沸概龄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,420評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽私杜。三九已至蚕键,卻和暖如春救欧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背锣光。 一陣腳步聲響...
    開封第一講書人閱讀 33,531評論 1 272
  • 我被黑心中介騙來泰國打工笆怠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人誊爹。 一個月前我還...
    沈念sama閱讀 48,995評論 3 377
  • 正文 我出身青樓蹬刷,卻偏偏與公主長得像,于是被迫代替她去往敵國和親频丘。 傳聞我的和親對象是個殘疾皇子办成,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,585評論 2 359