理解Promise對象

Promise對象:

  • 一個保存異步操做事件的對象
  • 三種狀態,Pending、Fulfilled、Rejected。狀態只會由「Pending→Fulfilled」或者「Pending→Rejected」,且狀態改變就不會再變
/*Promise對象是由一個構造函數生成實例,接受函數爲參數
   函數的參數爲resolve和reject。這二者,也是函數*/
   
var promise = new Promise ( function(resolve , reject){
    
    /*一些異步操做*/
    
    if/*異步操做成功*/){
        //當調用resolve函數的時候,Promise對象狀態由,Pending → Fulfilled
        //將value值進行傳遞(通常是異步操做成功後的結果)
        resolve(value)
    }  
    else {
        //當調用reject函數的時候,Promise對象狀態由,Pending → Rejected
        //將error值進行傳遞
        reject(error)
    }    
})    

整體上來講,Promise對象,更像是一個事件的容器,但Promise對象狀態的改變並不受事件的完成而完成,而是由參數函數中的 resolve 和 reject 函數來指定它何時改變狀態。數組

好比下面代碼:promise

var promise = new Promise ( function(resolve , reject){

    let i = 0//標記事件已完成,傳字符串resolved值給.then()處理
    resolve(i)
i += 1 }) .then( //then方法是指,當Promise狀態由Pending改變爲Resolved時,當即調用 (value) = > { console.log(value) } )

---------------------------------------------------------------
最後輸出:
0

then()方法下面會繼續講,問題來了,上面代碼「 i += 1」是否會運行呢?再看異步

var promise = new Promise ( function(resolve , reject){

    resolve()
    console.log('A')
    setTimeout(() => { console.log('B') }, 3000)

}) .then(() = > { console.log('Resolved') })
---------------------------------------------------------------
前後輸出:
A
Resolved
B   //3000ms後輸出B

Promise對象在狀態改變後,內部的代碼仍是會運行。當內部同步任務所有執行完成後,再調用then()方法。所以前兩行最早輸出的是‘A’和‘Resolved’,因爲B是一個異步事件,因此在3000ms後被調用輸出。函數

若是想在狀態改變後直接結束,不執行以後的語句,最好不要將異步操做放在狀態改變語句以後!固然也能夠這樣:spa

var promise = new Promise ( function(resolve , reject){
    //在前面加上return
    return resolve()

    console.log('A')
    setTimeout(() => { console.log('B') }, 3000)

}) .then(() = > { console.log('Resolved') })
---------------------------------------------------------------
最後只輸出:
Resolved

原型方法 —— then()

  • 該方法是定義在Promise對象原型上的方法,即Promise.prototype.then()
  • 且then()方法返回一個新Promise實例

顧名思義,Promise實例狀態改變後,要作什麼。該方法爲其添加了回調函數。Promise實例有兩種狀態,天然也提供了兩種回調(Resolved 和 Rejected)prototype

上面已經簡單涉及了該方法,這裏整理一下:code

var promise = new Promise ( function(resolve , reject){
    //作些什麼...
    if/*異步操做成功*/){ resolve(value) }  
    else {  reject(error) }    
}) .then( 
    //then方法接受兩個回調函數爲參數,如下

    //第一個Promise實例變爲Resolved狀態調用
    //函數中的參數value,接受Promise實例中resolve(value)傳遞的value值
    (value) => { /*success*/ },

    //(可選)第二個Promise實例變爲Rejected狀態調用
    ////函數中的參數error,接受Promise實例中reject(error)傳遞的error值
    (error) = > { /*failure*/ }
)
  • then()的鏈式調用

上面說了then方法返回一個新的Promise實例,那麼就能夠promise.then().then().then().then().then().....這樣的鏈式調用了。對象

var promise = new Promise ( function(resolve , reject){
    resolve(A)   
}) .then( (value) => {  //此處參數 value 接受 resolve(A) 中的傳遞值 A
    //輸出A
    console.log(value)
    return B
}).then( (value) => {  //此處參數 value 接受上一級then()方法中return的值
    //輸出B
    console.log(value)
}).then( (value) => {  //上一個then方法無return時
    //輸出undefined
    console.log(value)
})
-----------------------------------------------------------------
前後在控制檯上輸出:
A
B
undefined

若then()方法中傳入的不是函數,則在鏈式調用中,此then()方法會被忽略,值會傳入下一個then方法中blog

var promise = new Promise ( function(resolve , reject){
    resolve(A)   
}) .then(1)  //這個then方法被忽略
  .then( (value) => {console.log(value)}  )
-----------------------------------------------------------------
控制檯上輸出:
A

 

原型方法 —— catch()

  • Promise對象原型方法,Promise.prototype.catch()
  • 等同於.then( null , reject(error) )
  • catch()方法返回一個Promise對象

通常應用以下事件

var promise = new Promise ( function(resolve , reject){
    if/*異步操做成功*/){ resolve(value)}  
    else { reject(new Error ('promise'))}    
}) .then( (value)=>{
    if/*異步操做成功*/){ return A }  
    else { throw new Error('error_A') }  
}).then( (value)=>{
    if/*異步操做成功*/){ return B }  
    else { throw new Error('error_B') }  
}).then( (value)=>{
    if/*異步操做成功*/){return C }  
    else { throw new Error('error_C') }  
}).catch( (error)=>{
    /*此處catch捕獲以上從Promise對象到任意then方法所拋出的錯誤*/
    console.log(error) 
    //catch只能捕獲被調用以前拋出的錯誤,以後的錯誤如'error_D'就沒法捕獲
}).then( (value)=>{
    //上面的catch返回一個Promise對象所以能夠繼續調用then方法 
    if/*異步操做成功*/){return D }  
    else { throw new Error('error_D') }  
})

 

靜態方法

  • Promise.all()
  • Promise.race()
  • Promise.resolve()
  • Promise.reject()

Promise.all()

將多個Promise實例包裝,而且返回一個新的Promise實例

當包裝中全部的Promise狀態都變爲Resolved時,返回結果數組,數組中返回值的順序安裝包裝的數據排列

Promise.all([
   promise_A,
   promise_B,
   promise_C 
]).then(result=>{
  console.log(result)
})
---------------------------
//當promise_A,promise_B,promise_C狀態都爲Resolved時,result輸出一個結果數組:
[result_A,result_B,resultC]

當Promise集合中有一個Promise最終狀態爲Rejected,就會被Promise.all()的catch方法進行捕獲

Promise.all([
      new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log('A')
          reject(new Error('AAAAAAAAAAA'))
        }, 5000)
      }),
      new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log('B')
          reject(new Error('BBBBBBBBBBB'))
        }, 2000)
      }).catch(e => {
        return e
      })
    ]).then(result => {
      console.log(result)
    }).catch(e => {
      console.log(e)
    })
  }

----------------------------------------------
控制檯前後輸出:
B            //2s後輸出B
A            //5s後輸出A
AAAAAAAAAAA            //A輸出後當即輸出錯誤'AAAAAAAAAAA'

 上面代碼中爲何Promise. all最後捕獲的是錯誤'AAAAAAAAAAA'而不是‘BBBBBBBBBBB’。由於在第二個Promise實例中,2秒後雖然狀態變爲Rejected而且拋出了Error,可是被自身以後的catch方法捕獲了該錯誤且return。以前已經知道,Promise以後的then和catch方法其實返回的是一個新的Promise實例,若方法中沒有拋出新的錯誤,其後續的狀態就會變爲Resolved。而第一個實例拋出錯誤後,並未被後續方法捕獲,最後狀態爲Rejected,錯誤最終被外層Promise. all方法的後續catch所捕獲,最後輸出'AAAAAAAAAAA'。

Promis.race()

與上面方法同樣,一樣將多個Promise實例包裝成一個新的Promise實例。

Promise.race([P1,P2,P3])
    .then( value => { /*do something*/ } )
    .catch(e => { /*do something*/ })

Promise實例組中,P一、P二、P3誰的狀態先發生變化(Resolved 或 Rejected),Promise.race()狀態也發生改變,P1(or P2 or P3)的返回值傳遞給Promise.race()回調函數。

Promise.resolve()

將一個對象轉爲一個Promise對象,如下幾種狀況

let p = new Promise( (resolve,reject) => { resolve(1)} )
//傳入Promise對象p,返回仍是p
Promise.resolve(p)

//傳入一個非thenable對象(thenable對象,就是一個對象具備then方法,下面會說明),或者非對象
Promise.resolve('_JayKoo')
--------------------------------------
//上面代碼等同於
new Promise( (resolve,reject) =>{
    resolve('_JayKoo');
})

//thenable對象,具備then方法的對象
//then方法知足如下格式
let obj = {
    then(res , rej){     //then函數,參數知足Promise回調函數中的參數格式。then函數,至關於,Promise構造函數中的回調函數格式。
        if(/*Resolved*/){ res(value) }
        else { rej(error) }
    }
}

//將obj轉爲Promise對象,且當即調用then方法
Promise.resolve( obj )
---------------------------------------------------------------------------
//以上代碼的效果等同於當即執行了
new Promise( (res, rej) => {
    /*obj對象中的操做*/
    if(/*Resolved*/){ res(value) }
    else { rej(error) }
})

//不帶參數,當即生成一個Promise對象
//Promise.resolve()方法的執行,是在本輪註冊的全部同步腳本事件的結束時(非異步)
let p = Promise.resolve()

Promise.reject()

Promise.reject()一樣返回Promise對象.。

在Promise.resolve()中,傳入的參數由thenable對象和非thenable對象兩種狀況,且以後的參數調用狀況也不一樣。

但在Promise.reject()中,全部傳參都會被當作Error拋出。

let p = Promise.reject(thenable)
--------------------------------------
//等同於
let p = new Promise( (resolve,reject) => {
    //即便是個thenable對象,也會原封不動地將這個對象當作錯誤信息拋出
    reject(thenable)
})
--------------------------------------
p.catch( e => {
   console.log( e === thenable) 
})
//true
相關文章
相關標籤/搜索