promise

什么是Promise

Promise是抽象異步處理對(duì)象以及對(duì)其進(jìn)行各種操作的組件。 其詳細(xì)內(nèi)容在接下來(lái)我們還會(huì)進(jìn)行介紹,Promise并不是從JavaScript中發(fā)祥的概念。

Promise最初被提出是在 E語(yǔ)言中, 它是基于并列/并行處理設(shè)計(jì)的一種編程語(yǔ)言。

現(xiàn)在JavaScript也擁有了這種特性,這就是本書(shū)所介紹的JavaScript Promise。

另外,如果說(shuō)到基于JavaScript的異步處理,我想大多數(shù)都會(huì)想到利用回調(diào)函數(shù)。

Promise解決的問(wèn)題


我相信每個(gè)前端都遇到過(guò)這樣一個(gè)問(wèn)題,當(dāng)一個(gè)異步任務(wù)的執(zhí)行需要依賴(lài)另一個(gè)異步任務(wù)的結(jié)果時(shí),我們一般會(huì)將兩個(gè)異步任務(wù)嵌套起來(lái),這種情況發(fā)生一兩次還可以忍,但是發(fā)生很多次之后,你的代碼就會(huì)變成這個(gè)熊樣:

    async1(function(){
        async2(function(){
            async3(function(
                async4(funciton(){
                    async5(function(){
                        //(╯°□°)╯︵┻━┻
                        //...
                    });
                });
            )); 
        });
    });

這就是所謂的回調(diào)地獄,代碼層層嵌套,環(huán)環(huán)相扣,很明顯,邏輯稍微復(fù)雜一些,這樣的程序就會(huì)變得難以維護(hù)。

但去年ES2015的標(biāo)準(zhǔn)里,Promise的標(biāo)準(zhǔn)化,一定程度上解決了JavaScript的流程操作問(wèn)題。

Promise的基本用法


Promise類(lèi)似于 XMLHttpRequest,從構(gòu)造函數(shù) Promise 來(lái)創(chuàng)建一個(gè)新建新promise對(duì)象作為接口。

要想創(chuàng)建一個(gè)promise對(duì)象、可以使用new來(lái)調(diào)用Promise的構(gòu)造器來(lái)進(jìn)行實(shí)例化。

我們新建一個(gè)Promise的實(shí)例:

var _promise = new Promise(function(resolve, reject){
  setTimeout(function(){
    var rand = Math.random();
    if(rand<0.5){
        resolve("resolve"+rand);
    }else{
        reject("reject"+rand);
    }
  }, 1000)
})

運(yùn)行結(jié)果有兩種情況,如下圖


運(yùn)行結(jié)果

先跟大家介紹一下Promsie的基礎(chǔ)知識(shí)
Promise對(duì)象有三種狀態(tài),他們分別是:

  • pending:等待中或者進(jìn)行中,表示還沒(méi)得到結(jié)果
  • resolve(fulfilled):已經(jīng)完成,表示得到了我們想要的結(jié)果,可以繼續(xù)往下執(zhí)行
  • rejected:也表示得到結(jié)果,但是由于結(jié)果并非我們希望的,因此拒絕執(zhí)行
    這三種狀態(tài)不受外界影響,而且狀態(tài)只能從pending改變?yōu)閞esolved或者rejected,并且不可逆。

在Promise對(duì)象的構(gòu)造函數(shù)中,接受一個(gè)函數(shù)作為參數(shù),該函數(shù)就是用來(lái)處理Promise的狀態(tài)變化的,該函數(shù)接受兩個(gè)額外的函數(shù)resolve和reject,這兩個(gè)函數(shù)分別代表將當(dāng)前Promise置為fulfilled(解決)和rejected(拒絕)兩個(gè)狀態(tài)。

實(shí)際上Promise實(shí)例_promise是一個(gè)對(duì)象,不是一個(gè)函數(shù)。在聲明的時(shí)候,Promise傳遞的參數(shù)函數(shù)會(huì)立即執(zhí)行,因此Promise使用的正確姿勢(shì)是在其外層再包裹一層函數(shù)。如下:

var run = funciton(){
  var _promise = new Promise(function(resolve, reject){
    setTimeout(function(){
      var rand = Math.random();
      if(rand<0.5){
          resolve("resolve"+rand);
      }else{
          reject("reject"+rand);
      }
    },1000)
  })
  return _promise;
}
run();

這是Promise的正常用法

一個(gè)Promise必須提供一個(gè)then方法來(lái)獲取其值或原因。
Promise的then方法接受兩個(gè)參數(shù):promise.then(onFulfilled, onRejected)

then方法可以接受兩個(gè)回調(diào)函數(shù)作為參數(shù)。第一個(gè)回調(diào)函數(shù)是Promise對(duì)象的狀態(tài)變?yōu)閞esolved時(shí)調(diào)用,第二個(gè)回調(diào)函數(shù)是Promise對(duì)象的狀態(tài)變?yōu)閞ejected時(shí)調(diào)用。其中,第二個(gè)函數(shù)是可選的,不一定要提供。這兩個(gè)函數(shù)都接受Promise對(duì)象傳出的值作為參數(shù)。

接著上面創(chuàng)建的函數(shù)run(),我們來(lái)進(jìn)行對(duì)異步操作結(jié)果的處理:

run().then(function(data){
  //處理resolve的代碼
  console.log("Promise被置為resolve",data);
}, function(data){
  //處理reject的代碼
  console.log("Promise被置為reject",data);
})

如果異步操作獲得了我們想要的結(jié)果,那我們將調(diào)用處理resolve的函數(shù)(即onFulfilled方法),也就是在then的第一個(gè)作為參數(shù)的函數(shù)中進(jìn)行處理,獲取數(shù)據(jù);如果我們得到了錯(cuò)誤的結(jié)果,調(diào)用處理reject的函數(shù)(即 onRejected方法),也就是在then函數(shù)的第二個(gè)作為參數(shù)的函數(shù)中進(jìn)行處理,獲取錯(cuò)誤處理數(shù)據(jù)。

對(duì)reject后的處理,除了可以在.then 的第二個(gè)參數(shù)中處理,還可以在 .catch 方法中設(shè)置想要調(diào)用的函數(shù)。

以下是將對(duì)reject的處理放到.catch方法中:

run().then(function(data){
  //處理resolve的代碼
  console.log("Promise被置為resolve",data);
}).catch(function(data){
  //處理reject的代碼
  console.log("Promise被置為reject",data);
})

這樣,一個(gè)次完整的Promise調(diào)用就結(jié)束了。對(duì)于Promise的then()方法,then總是會(huì)返回一個(gè)Promise實(shí)例:
promise2 = promise1.then(onFulfilled, onRejected);
因此我們可以像上面面那樣接著對(duì)其返回值進(jìn)行 .then 調(diào)用,形如run().then().then().then().then().then().....
在一個(gè)then()方法調(diào)用異步處理成功的狀態(tài)時(shí),你既可以return一個(gè)確定的“值”,也可以再次返回一個(gè)Promise實(shí)例,當(dāng)返回的是一個(gè)確切的值的時(shí)候,then會(huì)將這個(gè)確切的值傳入一個(gè)默認(rèn)的Promise實(shí)例,并且這個(gè)Promise實(shí)例會(huì)立即置為fulfilled狀態(tài),以供接下來(lái)的then方法里使用。如下所示:

    run().then(function(data){
        console.log("第一次",data);
        return data;
    }).then(function(data){
        console.log("第二次",data);
        return data;
    }).then(function(data){
        console.log("第三次",data);
        return data;
    });
    /* 異步處理成功的打印結(jié)果:
        第一次 resolve0.49040459200760167d.js:18 
        第二次 resolve0.49040459200760167d.js:21 
        第三次 resolve0.49040459200760167
        由此可知then方法可以無(wú)限調(diào)用下去。
    */

根據(jù)這個(gè)特性,我們就可以將相互依賴(lài)的多個(gè)異步邏輯,進(jìn)行順序管理。
下面舉個(gè)例子:

//第一個(gè)異步任務(wù)
function run_a(){
 return new Promise(function(resolve,reject){
      //假設(shè)已經(jīng)進(jìn)行了異步操作,并獲得了數(shù)據(jù)
      resolve("step1");
  })
}
//第二個(gè)異步任務(wù)
function run_b(){
 return new Promise(function(resolve,reject){
      //假設(shè)已經(jīng)進(jìn)行了異步操作,并獲得了數(shù)據(jù)
      resolve("step2");
  })
}
//第三個(gè)異步任務(wù)
function run_c(){
 return new Promise(function(resolve,reject){
      //假設(shè)已經(jīng)進(jìn)行了異步操作,并獲得了數(shù)據(jù)
      resolve("step3");
  })
}

//連續(xù)調(diào)用
run_a().then(function(data){
  //返回一個(gè)Promise實(shí)例
  return run_b(data);
}).then(function(data){
  return run_c(data);
}).then(function(data){
  console.log(data);
})

用 async/await 來(lái)處理異步

最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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