JS中Promise理解與應(yīng)用

Promise 中文釋義:許諾,允諾;希望。意指我答應(yīng)你我會(huì)去做的,不管成功還是失敗我肯定會(huì)做的。

1、基礎(chǔ)介紹

PromiseES6一個(gè)新的特性,本身是個(gè)對(duì)象用于表示一個(gè)異步操作的最終完成 (或失敗), 及其結(jié)果值。創(chuàng)建一個(gè)Promise對(duì)象:

var promise1 = new Promise(function(resolve, reject) {}  );

傳入一個(gè)參數(shù)-函數(shù)function(resolve, reject) {},該函數(shù)本身兩個(gè)參數(shù)也是函數(shù)。Promise執(zhí)行構(gòu)造函數(shù)時(shí)立即執(zhí)行該函數(shù)function(resolve, reject) {},然后返回對(duì)象promise1。執(zhí)行結(jié)果要么成功、要么失敗:

  • 如果執(zhí)行完成調(diào)用resolve ,promise1狀態(tài)變?yōu)閒ulfilled 。
  • 如果失敗調(diào)用reject,promise1狀態(tài)變?yōu)閞ejected 。

Demo1——一個(gè)簡(jiǎn)單示例

//Demo1
var promise1 = new Promise(function(resolve, reject) {
    //這里通常執(zhí)行一個(gè)異步任務(wù)比如網(wǎng)絡(luò)數(shù)據(jù)請(qǐng)求等,成功返回調(diào)用resolve , 失敗reject
    resolve('執(zhí)行成功');
});

promise1.then(function(s){
    console.log('成功:' + s);
} , function(s){
    console.log("失敗:"  + s);
})

//結(jié)果輸出 成功:執(zhí)行成功

所以可以理解為promise用不同的狀態(tài)來標(biāo)記事件不同的處理結(jié)果,當(dāng)執(zhí)行完成時(shí)狀態(tài)為fulfilled , 失敗時(shí)狀態(tài)變?yōu)閞ejected。然后通過then方法綁定事件來處理不同的狀態(tài)。

Promise有三種狀態(tài)

pending: 初始狀態(tài),既不是成功,也不是失敗狀態(tài)。
fulfilled: 意味著操作成功完成。
rejected: 意味著操作失敗。

狀態(tài)變化只能有 pending-> fulfilled 或者 pending-> rejected 兩種方式,一旦狀態(tài)發(fā)生變化則保持固定不變。

2、方法介紹

then方法 ,原型 then(onFulfilled[, onRejected])

如上所述通過then方法對(duì)promise對(duì)象綁定處理事件 ,它最多需要有兩個(gè)參數(shù):Promise 的成功和失敗情況的回調(diào)函數(shù)。
當(dāng)成功時(shí)執(zhí)行第一個(gè)參數(shù)onFulfilled的回調(diào)處理,失敗執(zhí)行第二個(gè)參數(shù)onRejected的回調(diào)處理,然后返回一個(gè) 新的Promise對(duì)象,然后可以繼續(xù)添加then方法處理回調(diào),以此可形成鏈?zhǔn)秸{(diào)用。

then方法是個(gè)很重要的方法,下面我們結(jié)合各種情況來示例說明

注意兩個(gè)參數(shù)是可選的
如果調(diào)用 then 的 Promise 的狀態(tài)(fulfillment 或 rejection)發(fā)生改變,但是 then 中并沒有關(guān)于這種狀態(tài)的回調(diào)函數(shù),那么 then 將創(chuàng)建一個(gè)沒有經(jīng)過回調(diào)函數(shù)處理的新 Promise 對(duì)象,這個(gè)新 Promise 只是簡(jiǎn)單地接受調(diào)用這個(gè) then 的原 Promise 的終態(tài)作為它的終態(tài)。

Demo2——then方法沒有回調(diào)處理參數(shù)(無任何參數(shù))

//demo2---then沒有回調(diào)處理參數(shù)
var promise1 = new Promise(function(resolve, reject) {
    //這里通常一個(gè)異步任務(wù)比如網(wǎng)絡(luò)數(shù)據(jù)請(qǐng)求等,成功返回調(diào)用resolve , 失敗reject
    resolve('執(zhí)行成功');
});

var promise2 = promise1.then()
promise2.then(function(v){
    console.log("v: " + JSON.stringify(v));
})

//或直接這樣
/*promise1.then().then(function(v){
    console.log("v: " + JSON.stringify(v));
})*/

//輸出 v: "執(zhí)行成功"

新生成的對(duì)象promise2 狀態(tài)直接是完成狀態(tài),接收上一級(jí)傳遞的參數(shù),然后執(zhí)行then中成功回調(diào)處理。

如果執(zhí)行的reject('失敗'),則會(huì)拋出一個(gè)錯(cuò)誤異常,需要catch方法來捕獲。

關(guān)于then返回值

當(dāng)一個(gè) Promise 完成(fulfilled)或者失?。╮ejected)時(shí),返回函數(shù)將被異步調(diào)用(由當(dāng)前的線程循環(huán)來調(diào)度完成)。具體的返回值依據(jù)以下規(guī)則返回。如果 then 中的回調(diào)函數(shù):

  • 1、返回了一個(gè)值,那么 then 返回的 Promise 將會(huì)成為接受狀態(tài),并且將返回的值作為接受狀態(tài)的回調(diào)函數(shù)的參數(shù)值。
  • 2、沒有返回任何值,那么 then 返回的 Promise 將會(huì)成為接受狀態(tài),并且該接受狀態(tài)的回調(diào)函數(shù)的參數(shù)值為 undefined。
  • 3、拋出一個(gè)錯(cuò)誤,那么 then 返回的 Promise 將會(huì)成為拒絕狀態(tài),并且將拋出的錯(cuò)誤作為拒絕狀態(tài)的回調(diào)函數(shù)的參數(shù)值。
  • 4、返回一個(gè)已經(jīng)是接受狀態(tài)的 Promise,那么 then 返回的 Promise 也會(huì)成為接受狀態(tài),并且將那個(gè) Promise 的接受狀態(tài)的回調(diào)函數(shù)的參數(shù)值作為該被返回的Promise的接受狀態(tài)回調(diào)函數(shù)的參數(shù)值。
  • 5、返回一個(gè)已經(jīng)是拒絕狀態(tài)的 Promise,那么 then 返回的 Promise 也會(huì)成為拒絕狀態(tài),并且將那個(gè) Promise 的拒絕狀態(tài)的回調(diào)函數(shù)的參數(shù)值作為該被返回的Promise的拒絕狀態(tài)回調(diào)函數(shù)的參數(shù)值。
  • 6、返回一個(gè)未定狀態(tài)(pending)的 Promise,那么 then 返回 Promise 的狀態(tài)也是未定的,并且它的終態(tài)與那個(gè) Promise 的終態(tài)相同;同時(shí),它變?yōu)榻K態(tài)時(shí)調(diào)用的回調(diào)函數(shù)參數(shù)與那個(gè) Promise 變?yōu)榻K態(tài)時(shí)的回調(diào)函數(shù)的參數(shù)是相同的。

Demo3——then方法中直接返回一個(gè)值

    //demo3---then直接返回一個(gè)值
    var promise1 = new Promise(function(resolve, reject) {
        //這里通常一個(gè)異步任務(wù)比如網(wǎng)絡(luò)數(shù)據(jù)請(qǐng)求等,成功返回調(diào)用resolve , 失敗reject
        resolve('執(zhí)行成功');
    });
    
    var promise2 = promise1.then(
        function(value){
            return value;
        }
    )
    
    promise2.then(function(v){
        console.log("--v: " + JSON.stringify(v));
    })
    //輸出--v: "執(zhí)行成功"

then 回調(diào)總會(huì)返回一個(gè)promise對(duì)象,這個(gè)對(duì)象可以是隱式自動(dòng)生成的,也可以是我們顯示創(chuàng)建的。然后根據(jù)不同的狀態(tài)在執(zhí)行相應(yīng)的回調(diào)處理。

catch方法 ,原型 catch(onRejected)

用于處理promise失敗時(shí)錯(cuò)誤捕獲

Demo4——catch方法

    //demo4---catch方法
    var promise1 = new Promise(function(resolve, reject) {
        //這里通常一個(gè)異步任務(wù)比如網(wǎng)絡(luò)數(shù)據(jù)請(qǐng)求等,成功返回調(diào)用resolve , 失敗reject
        reject('執(zhí)行失敗');
    });
    
    var promise2 = promise1.then(function(value){
        console.log("執(zhí)行成功" + value);//這里不會(huì)走到這里
    }/*,function(value){//如果放開這里,下面的catch 不會(huì)執(zhí)行
        console.log('失敗:' + value);
    }*/
        
    ).catch(function(err){
        console.log('err:' + err);
        return 'err promise'
    })
    
    console.log(promise2);

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


image.png

如果then中有reject處理失敗的回調(diào),則不會(huì)執(zhí)行catch。其實(shí)它的行為與調(diào)用Promise.prototype.then(undefined, onRejected) 相同。 (事實(shí)上, calling obj.catch(onRejected) 內(nèi)部calls obj.then(undefined, onRejected)).

所以可以理解為 catch()等價(jià)于 then(undefined, onRejected)) , 但是使用catch來處理錯(cuò)誤更合適。因?yàn)樗部梢蕴幚韙hen成功回調(diào)處理中拋出的錯(cuò)誤。

可以看出catch中本身返回一個(gè)promise對(duì)象且狀態(tài)已完成。如果 catch中拋出一個(gè)錯(cuò)誤或返回一個(gè)本身失敗的 Promise , 通過 catch() 返回的Promise 被rejected;否則,它將顯示為成功(resolved)。

Promise.reject(reason)

生成一個(gè)狀態(tài)已失敗的promise對(duì)象

Promise.resolve(value)

生成一個(gè)狀態(tài)已完成的promise對(duì)象

all(iterable) 方法

Promise.all(iterable)

參數(shù)iterable :一個(gè)包含至少一個(gè)promise對(duì)象的數(shù)組。

類似于與操作,必須全部執(zhí)行完成才觸發(fā)接下來的操作。

方法返回一個(gè)新的 Promise 實(shí)例,此實(shí)例在 iterable 參數(shù)內(nèi)所有的 promise 都“完成(resolved)”或參數(shù)中不包含 promise 時(shí)回調(diào)完成(resolve);如果參數(shù)中 promise 有一個(gè)失?。╮ejected),此實(shí)例回調(diào)失?。╮eject),失敗原因的是第一個(gè)失敗 promise 的結(jié)果。

如果我們有多個(gè)異步任務(wù)處理,最后要監(jiān)聽全部執(zhí)行完成,此時(shí)all方法就很合適。

race()

Promise.race(iterable)
參數(shù)iterable :一個(gè)包含至少一個(gè)promise對(duì)象的數(shù)組。

此類似于或操作,只要有一個(gè)完成或失敗就算結(jié)束。任意一個(gè)子promise執(zhí)行成功或失敗后就會(huì)生成一個(gè)新的promise,狀態(tài)就是第一個(gè)promise的狀態(tài)。

Demo5—— race方法

    //race方法
    var promise1 = new Promise(function(resolve,reject){
        setTimeout(function(){
            resolve('promise1 完成');
        } , 3000);
    })
    
    var promise2 = new Promise(function(resolve,reject){
        setTimeout(function(){
            resolve('promise2 完成');
        } , 1500);
    })
    
    var promise3 = new Promise(function(resolve,reject){
        setTimeout(function(){
            resolve('promise3 完成');
        } , 2000);
    })
    
    Promise.race([promise1,promise2,promise3]).then(function(value){
        console.log("value: " + JSON.stringify(value));
    })


//輸出 value: "promise2 完成"

promise2最先執(zhí)行,所以其執(zhí)行完成后就結(jié)束流程。

常用的方法基本以上幾個(gè),剩下的就是結(jié)合實(shí)際場(chǎng)景應(yīng)用了。

3、Promise常見應(yīng)用

Demo6—— promise添加多個(gè)方法

    var promise1 = new Promise(function(resolve,reject){
        resolve('執(zhí)行完成');
    })
    
    promise1.then(function(value){
        console.log('1----' + value);
    })
    
    promise1.then(function(value){
        console.log('2----' + value);
    })
    
    promise1.then(function(value){
        console.log('3----' + value);
    })

輸出:


image.png

對(duì)同一個(gè)promise對(duì)象添加多個(gè)處理方法,就是相當(dāng)于同時(shí)監(jiān)聽一個(gè)事件。

Demo7 ——監(jiān)聽多個(gè)異步任務(wù)全部完成

    var promise1 = new Promise(function(resolve,reject){
        setTimeout(function(){
            console.log('promise1 完成');
            resolve('promise1 完成');
        } , 3000);
    })
    
    var promise2 = new Promise(function(resolve,reject){
        setTimeout(function(){
            console.log('promise2 完成');
            resolve('promise2 完成');
        } , 1500);
    })
    
    var promise3 = new Promise(function(resolve,reject){
        setTimeout(function(){
            console.log('promise3 完成');
            resolve('promise3 完成');
        } , 2000);
    })
    
    Promise.all([promise1,promise2,promise3]).then(function(value){
        console.log("value: " + JSON.stringify(value));
    })

輸出結(jié)果:


image.png

all方法返回新的promise對(duì)象,回調(diào)處理函數(shù)參數(shù)和實(shí)際執(zhí)行完成順序無關(guān),只和添加的順序有關(guān)。

Demo8 ——實(shí)現(xiàn)鏈?zhǔn)讲僮?/code>
特別是一個(gè)異步任務(wù)請(qǐng)求數(shù)據(jù)要用于下一個(gè)任務(wù)操作的這種必須的先后次序總,尤為重要。

修改demo7要順序執(zhí)行:即依次輸出promise1完成-promise2完成-promise3完成。

    var promise1 = new Promise(function(resolve,reject){
        setTimeout(function(){
            console.log('promise1 完成');
            resolve('promise1 完成');
        } , 3000);
    }).then(function(value){
        return new Promise(function(resolve,reject){
            setTimeout(function(){
                console.log('promise2 完成');
                resolve('promise2 完成');
            } , 1500);
        });
        
        return p
    }).then(function(value){
        return new Promise(function(resolve,reject){
            setTimeout(function(){
                console.log('promise3 完成');
                resolve('promise3 完成');
            } , 2000);
        });
        
        return p
    })

此時(shí)promise1對(duì)象就是最后一個(gè)then方法返回的對(duì)象,狀態(tài)為接受狀態(tài),并且該接受狀態(tài)的回調(diào)函數(shù)的參數(shù)值為 promise3 完成。

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

image.png

4、總結(jié)

  • promise一旦開始不能終止。
  • 狀態(tài)一旦改變就固定了,不會(huì)在被修改。
  • 在異步操作中拋出錯(cuò)誤異常無法被捕獲。

Promise主要用于異步處理,根據(jù)不同的狀態(tài)執(zhí)行相應(yīng)的回調(diào)處理,有點(diǎn)類似其他系統(tǒng)的狀態(tài)機(jī)的概念。

ok , 關(guān)于Promise的介紹到此結(jié)束,理解了這些在實(shí)際應(yīng)用中為我們多任務(wù)的異步處理又多一種選擇。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容