ES6 深入了解Promise對象

Promise對象的含義

所謂的Promise就是一個對象,用來傳遞異步操作的消息提澎,它代表某個未來才會知道結(jié)果的事件(異步操作)扫尖。

Promise對象特點

1. 該對象的狀態(tài)不受外界影響卸夕。
Promise代表一個異步操作逝慧,它有三種狀態(tài):
Pending (進(jìn)行中)、Resolved(已完成)捌浩、Rejected (已失敗)
只有異步操作的結(jié)果可以決定當(dāng)前是那一種狀態(tài)放刨,任何其他操作都不能改變這個狀態(tài)。這也是 “Promise” 這個名字的由來尸饺。

2. 一旦狀態(tài)改變就不會再變进统,任何操作都能得到這個結(jié)果助币。
Promise對象的狀態(tài)改變只有兩種可能
Pending變?yōu)?strong>Resolved或者從 Pending變?yōu)?strong>Rejected 。只要其中一個發(fā)生麻昼,狀態(tài)就凝固不會再變奠支,一直保持這個結(jié)果。

Promise對象缺點

  • 首先抚芦,無法取消Promise倍谜,一旦新建它就會立即執(zhí)行,無法中途取消叉抡。
  • 其次尔崔,如果不設(shè)置回調(diào)函數(shù),Promise內(nèi)部拋出的錯誤不會反應(yīng)到外部褥民。
  • 再者季春,當(dāng)處于Pending狀態(tài)時,無法得知目前進(jìn)展到哪一個階段(剛剛開始還是即將完成)消返。

基本用法

Promise對象是一個構(gòu)造函數(shù)载弄,用來生成Promise實例。

var promise = new Promise(function(resolve,reject){
   //邏輯代碼
    if(/*異步成功*/){
       resolve(value);
     } else{
      reject(error)
    }
});

Promise構(gòu)造函數(shù)接受一個函數(shù)作為參數(shù)撵颊,改函數(shù)的兩個參數(shù)分別是resolvereject宇攻,它們是兩個函數(shù),由javaScript引擎提供倡勇,不用自己部署逞刷。

  • resolve函數(shù)的作用,將Promise函數(shù)的狀態(tài)從 未完成 變成 成功(從Pending變?yōu)?strong>Resolved),在異步操作成功時調(diào)用妻熊,并將異步操作的結(jié)果作為參數(shù)傳遞出去夸浅;
  • reject函數(shù)的作用,將Promise函數(shù)的狀態(tài)從 未完成 變成 失敗(從Pending變?yōu)?strong>Rejected),在異步操作失敗時調(diào)用扔役,并將異步操作報出的錯誤作為參數(shù)傳遞出去帆喇;

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

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

then方法可以接受兩個回調(diào)函數(shù)作為參數(shù)厅目。第一個函數(shù)是Promise對象的狀態(tài)變?yōu)?strong>Resolved時調(diào)用番枚,第二個是變?yōu)?strong>Rejected時調(diào)用。第二個參數(shù)是可選的损敷,不一定要提供。這兩個函數(shù)都接受Promise對象傳出的值作為參數(shù)深啤。

function timeout(ms){
  return new Promise((resolv,reject)=>{
   setTimeout(resolve,ms,'done')
  });
}
timeout(100).then(function(value){
   console.log(value)
})

↑上面代碼timeout返回一個Promise實例拗馒,表示一段時間以后才會發(fā)生的結(jié)果。過了指定的時間(ms)以后溯街,Promise實例的狀態(tài)變?yōu)?strong>Resolved诱桂,就會觸發(fā)then方法綁定的回調(diào)函數(shù)洋丐。


function loadImageAsync(url){
    return new Promise(function(resolve,reject){
       var image = new Image();
       image.onload = function(){
            resolve(image);
       };
       image.onerror = function(){
           reject(new Error("無法加載圖片,地址:" + url ));
      }; 
      image.src = url;
   })
}

↑上面是一個異步加載圖片的例子.


var  getJSON = function(url){
  var promise = new Promise(function(resolve,reject){
        var client = new XMLHttpRequest();
        client.open('GET',url);
        client.onreadystatechange = handler;
        client.responseType = 'json';
        client.setRequestHeader('Accept','application/json');
        client.send();
        function handler(){
            if(this.readyState !==4) {
               return;
             }
             if(this.readyState !==200) {
               resolve(this.response)
             }else{
               reject(new Error(this.statusText));
             }
         };
    });
      return promise;
}挥等;
getJSON("/posts.json").then(function(json){
     console.log('contents:'+ json)
},function(error){
     console.error('出錯了',error);
});

上面的代碼中友绝,getJSON是對XMLHttpRequest對象的封裝,用于發(fā)出一個針對JSON數(shù)據(jù)的HTTP請求肝劲,并返回一個Promise對象迁客。需要注意的是,在getJson內(nèi)部辞槐,resolve函數(shù)和reject函數(shù)調(diào)用時帶有參數(shù)掷漱。

Promise.prototype.then();

Promise的實例具有then方法。也就是說榄檬,then方法是定義在原型對象Promise.prototype上的卜范。
它的作用是為Promise的實例添加狀態(tài)改變時的回調(diào)函數(shù)。
then方法返回的是一個新的Promise實例(注意鹿榜,不是原來那個Promise的實例)

var p1 = new Promise(function(resolve,reject){
});
var p2 = p1.then(function(){})
p1
//Promise {<pending>}
p2
//Promise {<pending>}
p1 == p2
//false

↑上面可以看到p2是then方法返回的新的Promise實例海雪,因此可以采用鏈?zhǔn)綄懛ǎ?strong>then方法后面再調(diào)用then方法舱殿。

getJSON("/posts.json").then(function(json){
    return  json.post;
}).then(function(post){
    //....
});

↑上面的代碼使用then方法一次指定了兩個回調(diào)函數(shù)奥裸。第一個回調(diào)函數(shù)完成以后,會將返回結(jié)果作為參數(shù)傳入第二個回調(diào)函數(shù)怀薛。

Promise.prototype.catch();

Promise.prototype.catch()Promise.prototype.then(null,reject)的別名刺彩,用于指定發(fā)生錯誤時的回調(diào)函數(shù)。

getJSON("/posts.json").then(function(json){
    return  json.post;
}).then(post=> {
    //....
}).cath(err=>{
  /....
})

如果異步過程中拋出錯誤枝恋,機(jī)會被catch方法指定的回調(diào)函數(shù)所捕獲创倔。(條件是Promise狀態(tài)還未變成resolved,否則拋出的錯是無效的。)

var p1 = new Promise(function(resilve,reject){
   throw new Error('test')
});
p1.then(success=>{}).catch(err=>{console.log(err)})
 // Error: test

var p2 = new Promise(function(resilve,reject){
   resilve('success');
   throw new Error('test')
});
p2.then(suc=>{console.log(suc)}).catch(err=>{console.log(err)})
//success

Promise對象的錯誤具有“冒泡”性質(zhì)焚碌,會一直向后傳遞畦攘,直到被捕獲位置,也就是說錯誤總是會被下一個catch語句捕獲十电。

getJSON("/posts.json").then(function(json){
    return  json.post;
}).then(post=> {
    //....
}).cath(err=>{
 //處理前面三個Promise產(chǎn)生的錯誤
})

正規(guī)的寫法不要在then方法中寫rejected的狀態(tài)回調(diào)函數(shù)(then的第二個參數(shù))知押,而是使用catch方法。

catch方法返回的也是一個 Promise實例鹃骂,所以在 Promise方法在未拋出錯誤的時候台盯,catch方法后面還可以繼續(xù)調(diào)用then方法。

Promise.all();

Promise.all方法用于將多個Promise實例包裝成一個新的Promise實例畏线。

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

Promise.all接受一個數(shù)組作為參數(shù)静盅,如果非數(shù)組,就會先調(diào)用Promise.resolve方法寝殴,將參數(shù)轉(zhuǎn)為Promise實例蒿叠,再進(jìn)一步處理明垢。

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中的狀態(tài)有一個變成Rejected鬓照,此時第一個被Rejected實例返回值會傳遞給p的回調(diào)函數(shù)。

Promise.race();

Promise.all();同樣是將多個Promise實例包裝成一個新的Promise實例孤紧。

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

Promise.race的參數(shù)規(guī)則和上面講到的Promise.all方法一樣豺裆。

p的狀態(tài)規(guī)則不一樣,只要p1, p2, p3的狀態(tài)中有一個實例率先改變,p的狀態(tài)也跟著改變号显。

Promise.resolve();

有時我們需要把現(xiàn)有對象轉(zhuǎn)為Promise對象臭猜,Promise.resolve方法就可以做到。

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

上面的代碼將jQuery生成的deferred對象轉(zhuǎn)為新的Promise對象押蚤。

Promise.resolve('foo');

↑上面等價于下面的寫法蔑歌;

new Promise(resolve=>resolve('foo'))

Promise.reject();

Promise.reject(reason) 也返回一個新的Promise實例,狀態(tài)為rejected,它的的參數(shù)reason會被傳遞給實例的回調(diào)函數(shù)揽碘。

var p = Promise('出錯了4瓮馈!')雳刺;

↑等同于↓

var p = new Promise((resolve,reject)=>reject('出錯了=僭睢!'));
p.then(null,(s)=>{console.log(s)})
//出錯了R磋搿本昏!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市枪汪,隨后出現(xiàn)的幾起案子涌穆,更是在濱河造成了極大的恐慌,老刑警劉巖雀久,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宿稀,死亡現(xiàn)場離奇詭異,居然都是意外死亡赖捌,警方通過查閱死者的電腦和手機(jī)原叮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來巡蘸,“玉大人奋隶,你說我怎么就攤上這事≡没模” “怎么了唯欣?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長搬味。 經(jīng)常有香客問我境氢,道長,這世上最難降的妖魔是什么碰纬? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任萍聊,我火速辦了婚禮,結(jié)果婚禮上悦析,老公的妹妹穿的比我還像新娘寿桨。我一直安慰自己,他們只是感情好强戴,可當(dāng)我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布亭螟。 她就那樣靜靜地躺著,像睡著了一般骑歹。 火紅的嫁衣襯著肌膚如雪预烙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天道媚,我揣著相機(jī)與錄音扁掸,去河邊找鬼。 笑死最域,一個胖子當(dāng)著我的面吹牛谴分,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播羡宙,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼狸剃,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了狗热?” 一聲冷哼從身側(cè)響起钞馁,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎匿刮,沒想到半個月后僧凰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡熟丸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年训措,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡绩鸣,死狀恐怖怀大,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情呀闻,我是刑警寧澤化借,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站捡多,受9級特大地震影響蓖康,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜垒手,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一蒜焊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧科贬,春花似錦泳梆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至唐责,卻和暖如春鳞溉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鼠哥。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工熟菲, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人朴恳。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓抄罕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親于颖。 傳聞我的和親對象是個殘疾皇子呆贿,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,440評論 2 348

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

  • Promise 對象 Promise 的含義 Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函...
    neromous閱讀 8,700評論 1 56
  • Promiese 簡單說就是一個容器森渐,里面保存著某個未來才會結(jié)束的事件(通常是一個異步操作)的結(jié)果做入,語法上說,Pr...
    雨飛飛雨閱讀 3,352評論 0 19
  • 一同衣、Promise的含義 Promise在JavaScript語言中早有實現(xiàn)竟块,ES6將其寫進(jìn)了語言標(biāo)準(zhǔn),統(tǒng)一了用法...
    Alex灌湯貓閱讀 820評論 0 2
  • 目錄:Promise 的含義基本用法Promise.prototype.then()Promise.prototy...
    BluesCurry閱讀 1,490評論 0 8
  • 1. Promise 的含義 所謂Promise耐齐,簡單說就是一個容器浪秘,里面保存著某個未來才會結(jié)束的事件(通常是一個...
    ROBIN2015閱讀 483評論 0 0