ES6之Promise

特點(diǎn)

  • Promise能將回調(diào)分離出來(lái),在異步操作執(zhí)行之后,用鏈?zhǔn)椒椒▓?zhí)行回調(diào),雖然es5用封裝函數(shù)也能實(shí)現(xiàn),但是如果有多層異步的話,就會(huì)顯得比較繁瑣,而Promise用鏈?zhǔn)絼t更加直觀優(yōu)雅.

  • Promise對(duì)象不受外界的影響.有三種狀態(tài).pending進(jìn)行中,fulfilled已成功,rejected已失敗.只有異步操作的結(jié)果可以決定當(dāng)前是哪一種狀態(tài).

  • 狀態(tài)一旦改變,就不會(huì)再變.

語(yǔ)法

Promise 譯為承諾,即為如果我做到了,會(huì)怎么怎么樣,沒做到,會(huì)怎么怎么樣,es6中的promise大致表達(dá)的意思也是這樣,用于一個(gè)異步操作最終完成或者沒完成及其結(jié)果的表示.

  • 語(yǔ)法
    var promise = new Promise(
        //executor
        function(resolve,reject){
           if(/*異步成功*/){resolve(value)}
           else{reject(error)}
       }
    )
    promise.then(function(value){
    //success
    },funtion(){
    //fail
    })
    

參數(shù)

  • 參數(shù): 為回調(diào)函數(shù),回調(diào)函數(shù)的參數(shù)為resolve和reject

  • resolve和reject分別表示異步操作成功后的回調(diào)函數(shù)和異步操作失敗的回調(diào)函數(shù),

  • resolve函數(shù),將Promise的狀態(tài)改為fulfilled;reject改為rejected;

  • Promise實(shí)例創(chuàng)建成功后,then方法分別指定不同狀態(tài)的回調(diào)函數(shù)

參數(shù)executor補(bǔ)充點(diǎn)

  • 回調(diào)函數(shù)executor在Promise構(gòu)造函數(shù)執(zhí)行的時(shí)候同步執(zhí)行

    //注意打印結(jié)果的順序
    let pro = new Promise(function(resolve,reject){
        console.log('inPromise')
        resolve('成功后的回調(diào)')
     });
    pro.then((data) => console.log(data))
    console.log('notInPromise')
    
    // inPromise
    // notInPromise
    // '成功后的回調(diào)'
    
  • 同步執(zhí)行是什么意思呢,以上代碼中,我只是new了一個(gè)實(shí)例 pro,但是并沒有去調(diào)用pro,最終結(jié)果仍然打印出了內(nèi)容,因?yàn)閚ew的過(guò)程和executor的執(zhí)行是同時(shí)的,所以在創(chuàng)建實(shí)例的時(shí)候,回調(diào)函數(shù)就已經(jīng)在執(zhí)行了.

  • 有時(shí)候我們只是想創(chuàng)建實(shí)例,并不想去執(zhí)行,該怎么辦呢?一般的解決辦法就是把它包裝在一個(gè)函數(shù)中.需要使用的時(shí)候再去執(zhí)行這個(gè)包裝函數(shù).

    function promisBox(){
     let pro = new Promise(function(resolve,reject){
        console.log('inPromise')
        resolve('成功后的回調(diào)')
     });
    console.log('notInPromise')
    return pro;
    }
    promisBox().then((data) => console.log(data))
    

基本用法

promise.then(onFulfilled, onRejected)

如果 onFulfilled, onRejected不是函數(shù),其必須被忽略;若為函數(shù),僅可被調(diào)用一次!

onFulfilled在Promise執(zhí)行結(jié)束前不可被調(diào)用.

onRejected在被拒絕執(zhí)行前不可被調(diào)用.

  • 創(chuàng)建實(shí)例之后,調(diào)用.then,then可以接收兩個(gè)回調(diào)函數(shù)當(dāng)作參數(shù).第一個(gè)參數(shù)是異步執(zhí)行成功的時(shí)候調(diào)用,第二個(gè)則為失敗的時(shí)候調(diào)用,可省略.

    //還用上面的例子
    function promisBox(age){
     let pro = new Promise(function(resolve,reject){
        if(age > 18){
            resolve('成功后的回調(diào)')
        }else{
         reject('失敗后的回調(diào)')
        }
     });
    return pro;
    }
    promisBox(24).then(
        (res) => console.log(res), //接收上面resolve中的參數(shù)
        (error) => console.log(error) //接收上面reject中的參數(shù)
    )
    //'成功后的回調(diào)'
    promisBox(17).then(
        (res) => console.log(res), //接收上面resolve中的參數(shù)
        (error) => console.log(error) //接收上面reject中的參數(shù)
    )
    //'失敗后的回調(diào)'
    
  • 除了then之外,還有catch方法;catch和then里的第二個(gè)參數(shù)效果一樣,不過(guò)多了一個(gè)功能,如果then第一個(gè)參數(shù)內(nèi)代碼出錯(cuò),并不會(huì)報(bào)錯(cuò)卡死,而是會(huì)進(jìn)到catch方法內(nèi).

    function promisBox(age){
     let pro = new Promise(function(resolve,reject){
        if(age > 18){
            resolve('成功后的回調(diào)')
        }else{
         reject('失敗后的回調(diào)')
        }
     });
    return pro;
    }
    promisBox(24)
        .then(
            (res) => console.log(xixi,res), //xixi變量沒有定義,進(jìn)入到catch方法,不報(bào)錯(cuò)
        )
        .catch(error => console.log(error)) //接收then第一個(gè)參數(shù)內(nèi)的報(bào)錯(cuò)信息
    // failed
    // ReferenceError: xixi is not defined...
    

小例子

  • 案例1

    var promise2 = new Promise((resolve,reject) => {
        setTimeout(function (){resolve('success')},250)
    })
    promise2.then((suc) => console.log(suc)) // 'success'
    
  • 案例2(摘自阮一峰老師,鏈接在最后)

    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.status === 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('出錯(cuò)了', error);
    });
    

對(duì)象方法

Promise.prototype.then()

  • 如果有多層異步和回調(diào)

    function promisBox(){
         let pro = new Promise(function(resolve,reject){
            console.log('inPromise1')
            resolve('成功后的回調(diào)1')
         });
        console.log('notInPromise1')
        return pro;
    }
    function promisBox2(){
         let pro = new Promise(function(resolve,reject){
            console.log('inPromise2')
            resolve('成功后的回調(diào)2')
         });
        console.log('notInPromise2')
        return pro;
    }
    promisBox()
        .then((res) => {console.log(res);return promisBox2()})
        .then((res) => {console.log(res);return '也可以直接返回?cái)?shù)據(jù),作為參數(shù)'})
        .then((res) => {console.log(res)})
    //inPromise1
    //notInPromise1
    // 成功后的回調(diào)1
    // inPromise2
    // notInPromise2
    // 成功后的回調(diào)2
    // 也可以直接返回?cái)?shù)據(jù),作為參數(shù)
    
  • 一個(gè)異步的結(jié)果返回另一個(gè)異步操作

    var  promise1 = new Promise((resolve,reject) => {
        setTimeout(() => reject('reject'),3000)
    })
    var promise2 = new Promise((resolve,reject) => {
        setTimeout(() => resolve(promise1),1000)
    } )  
    promise2 //這里的then語(yǔ)句是promise1的事件了
        .then(res => console.log('success',res))
        .catch(error => console.log('failed',error))
    //三秒之后 打印出 'failed reject'
    

    promise1的狀態(tài)決定了promise2的狀態(tài),所以這個(gè)時(shí)候,所以沒有執(zhí)行promise1的resolve函數(shù)

Promise.prototype.catch()

Promise.prototype.catch() 等同于.then(null,reject)

  • 以下兩種寫法效果一樣,一般用第二種方法

    // 一
    var promise = new Promise(function(resolve, reject) {
      console.log(xixixixi)
    });
    promise
        .then(null,err => console.log('reject',err)) 
    // 二
    promise
        .catch(err => console.log('reject',err))
    // reject 
    // ReferenceError: xixixixi is not defined
    
  • Promise實(shí)例在resolve之后再有錯(cuò)誤,不會(huì)被捕獲.

    var promise = new Promise(function(resolve, reject) {
      resolve('success')
      console.log(xixixixi)
    });
    promise
        .then(res => console.log(res))
        .catch(err => console.log(err))
    // success
    
  • 任意一個(gè)then發(fā)生錯(cuò)誤的時(shí)候,都會(huì)被最后的catch捕獲到

    promise
        .then(res => console.log(res))
        .then(res => console.log(res))
        .then(res => console.log(res))
        .catch(err => console.log(err)) //以上三個(gè),任意一個(gè)出現(xiàn)錯(cuò)誤,都會(huì)被捕捉
    
  • catch返回的是Promise,所以之后可以繼續(xù).then

     var promise = new Promise(function(resolve, reject) {
      console.log(xixixixi)
     });
     promise
        .catch(err => console.log(err))
        .then(res => console.log('繼續(xù)執(zhí)行'))
    // ReferenceError: xixixixi is not defined
    // 繼續(xù)執(zhí)行
    
  • 上例換個(gè)順序

    var promise = new Promise(function(resolve, reject) {
      resolve('隨便')
    });
    promise
        .catch(err => console.log(err))
        .then(res => {console.log(res);console.log(xixixi)})
        //.catch(err => console.log(err))
    // 先打印出  '隨便'
    // 然后拋出錯(cuò)誤 ReferenceError: xixixi is not defined;
    // 之前都是打印出錯(cuò)誤,不影響運(yùn)行.這里是拋出錯(cuò)誤,停止運(yùn)行
    // 因?yàn)檫@里的then出現(xiàn)錯(cuò)誤,跟之前的catch無(wú)關(guān)了,錯(cuò)誤無(wú)法被捕獲
    

Promise.all()

Promise.all(iterable);

只有參數(shù)中的每個(gè)實(shí)例的狀態(tài)都編程fulfilled或者其中一個(gè)變?yōu)閞ejected,才會(huì)調(diào)用之后的回調(diào)函數(shù)

  • 首先看一段代碼,了解用法,還是用上面promiseBox的例子,下例中,參數(shù)為 promisBox 和 promisBox2 組成的數(shù)組,all的狀態(tài)是由數(shù)組中的值共同決定,只有每個(gè)值的狀態(tài)都是fulfilled,all的狀態(tài)才會(huì)變成fulfilled.返回值為一個(gè)數(shù)組.

    function promisBox(){
         let pro = new Promise(function(resolve,reject){
            resolve('成功后的回調(diào)1')
         });
        return pro;
    }
    function promisBox2(){
         let pro = new Promise(function(resolve,reject){
            resolve('成功后的回調(diào)2')
         });
        return pro;
    }
    
    var all = Promise.all([promisBox(),promisBox2()])
        .then((res) => console.log(res))
        .catch(err => console.log(err))
    // ["成功后的回調(diào)1", "成功后的回調(diào)2"]
    
  • 數(shù)組中有一個(gè)值的狀態(tài)為rejected,則all的狀態(tài)為rejected

    function promisBox(){
         let pro = new Promise(function(resolve,reject){
            resolve('成功后的回調(diào)1')
         });
        return pro;
    }
    function promisBox2(){
         let pro = new Promise(function(resolve,reject){
            resolve('成功后的回調(diào)2')
         });
        return pro;
    }
    
    function promisBox3(){
         let pro = new Promise(function(resolve,reject){
            console.log(xixixixi)
            resolve('成功后的回調(diào)3')
         });
        return pro;
    }
    var all = Promise.all([promisBox(),promisBox2(),promisBox3()])
        .then((res) => console.log(res))
        .catch(err => console.log(err))
    //ReferenceError: xixixixi is not defined
    
  • 如果參數(shù)實(shí)例中自己定義了catch,如果此參數(shù)的狀態(tài)是rejected,執(zhí)行的是它自己的catch,而不是all的catch

     function promisBox(){
         let pro = new Promise(function(resolve,reject){
            resolve('成功后的回調(diào)1')
         });
        return pro;
    }
    function promisBox2(){
         let pro = new Promise(function(resolve,reject){
            resolve('成功后的回調(diào)2')
         });
        return pro;
    }
    
    function promisBox3(){
         let pro = new Promise(function(resolve,reject){
            console.log(xixixixi)
            resolve('成功后的回調(diào)3')
         })
            .catch(err => console.log('promisBox3',err));
        return pro;
    }
    var all = Promise.all([promisBox(),promisBox2(),promisBox3()])
        .then((res) => console.log(res))
        .catch(err => console.log('all',err))
    // promisBox3 ReferenceError: xixixixi is not defined
    // ["成功后的回調(diào)1", "成功后的回調(diào)2", undefined]
    

    promisBox3首先是rejected,但是他有自己的catch,通過(guò)catch方法,返回一個(gè)新的Promise實(shí)例,這個(gè)新的實(shí)例狀態(tài)是fulfilled;因此最后all會(huì)執(zhí)行then的回調(diào)

Promise.race()

all的效果是,誰(shuí)執(zhí)行的最慢,就以誰(shuí)為基準(zhǔn)執(zhí)行回調(diào),而race相反,race譯為比賽,效果是誰(shuí)執(zhí)行的快,就以誰(shuí)為基準(zhǔn)去執(zhí)行回調(diào).
race的用法和all差不多.

  • 具體例子
     function promisBox(){
         let pro = new Promise(function(resolve,reject){
            //console.log(hahahaha)    第一個(gè)注釋
            resolve('成功后的回調(diào)1')
         });
        return pro;
    }
    function promisBox2(){
         let pro = new Promise(function(resolve,reject){
            setTimeout(function(){
                //console.log(hahahaha)  第二個(gè)注釋
                resolve('成功后的回調(diào)2')}
             ,2000)
         });
        return pro;
    }
    
    var race = Promise.race([promisBox(),promisBox2()])
        .then((res) => console.log(res))
        .catch(err => console.log(err))
    // 成功后的回調(diào)1
    //將第一個(gè)注釋取消  ReferenceError: hahahaha is not defined
    // 將第二個(gè)注釋取消   '成功后的回調(diào)1' 兩秒后拋出錯(cuò)誤hahahaha is not ...,停止運(yùn)行.
    

參考

阮一峰ES6入門
MDN

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市啥酱,隨后出現(xiàn)的幾起案子褒颈,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡哑姚,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門芜茵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)叙量,“玉大人,你說(shuō)我怎么就攤上這事九串〗逝澹” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵蒸辆,是天一觀的道長(zhǎng)征炼。 經(jīng)常有香客問(wèn)我,道長(zhǎng)躬贡,這世上最難降的妖魔是什么谆奥? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮拂玻,結(jié)果婚禮上酸些,老公的妹妹穿的比我還像新娘。我一直安慰自己檐蚜,他們只是感情好魄懂,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著闯第,像睡著了一般市栗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天填帽,我揣著相機(jī)與錄音蛛淋,去河邊找鬼。 笑死篡腌,一個(gè)胖子當(dāng)著我的面吹牛褐荷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嘹悼,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼叛甫,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了杨伙?” 一聲冷哼從身側(cè)響起其监,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎缀台,沒想到半個(gè)月后棠赛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哮奇,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡膛腐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鼎俘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哲身。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖贸伐,靈堂內(nèi)的尸體忽然破棺而出勘天,到底是詐尸還是另有隱情,我是刑警寧澤捉邢,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布脯丝,位于F島的核電站,受9級(jí)特大地震影響伏伐,放射性物質(zhì)發(fā)生泄漏宠进。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一藐翎、第九天 我趴在偏房一處隱蔽的房頂上張望材蹬。 院中可真熱鬧,春花似錦吝镣、人聲如沸堤器。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)闸溃。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間辉川,已是汗流浹背掂为。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留员串,地道東北人勇哗。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像寸齐,于是被迫代替她去往敵國(guó)和親欲诺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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

  • Promiese 簡(jiǎn)單說(shuō)就是一個(gè)容器渺鹦,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果扰法,語(yǔ)法上說(shuō),Pr...
    雨飛飛雨閱讀 3,358評(píng)論 0 19
  • 本文適用的讀者 本文寫給有一定Promise使用經(jīng)驗(yàn)的人毅厚,如果你還沒有使用過(guò)Promise塞颁,這篇文章可能不適合你,...
    HZ充電大喵閱讀 7,310評(píng)論 6 19
  • //本文內(nèi)容起初摘抄于 阮一峰 作者的譯文吸耿,用于記錄和學(xué)習(xí)祠锣,建議觀者移步于原文 概念: 所謂的Promise,...
    曾經(jīng)過(guò)往閱讀 1,239評(píng)論 0 7
  • 我已經(jīng)連續(xù)寫簡(jiǎn)書16天了咽安,雖然每天發(fā)布的時(shí)間不一樣伴网,有時(shí)候是下午,有時(shí)候是半夜妆棒。但確實(shí)堅(jiān)持寫了澡腾。 今天我發(fā)現(xiàn)一個(gè)小...
    百合手工閱讀 193評(píng)論 2 3
  • 一滴眼淚要流多久 才能忍住不思念 你不在身邊 我開始忘記了時(shí)間 江山不懂江山 誰(shuí)聽得見你的嗟嘆 世上有太多紛紛擾擾...
    北小音閱讀 247評(píng)論 1 1