Promise的學習和使用

語法

new Promise( function(resolve, reject) {...} /* executor */  );
複製代碼

executor是帶有 resolve 和 reject 兩個參數的函數 。Promise構造函數執行時當即調用executor 函數, resolve 和 reject 兩個函數做爲參數傳遞給executor(executor 函數在Promise構造函數返回新建對象前被調用)。resolve 和 reject 函數被調用時,分別將promise的狀態改成_fulfilled(完成)或rejected(失敗)。executor 內部一般會執行一些異步操做,一旦完成,能夠調用resolve函數來將promise狀態改爲_fulfilled,或者在發生錯誤時將它的狀態改成rejected。若是在executor函數中拋出一個錯誤,那麼該promise 狀態爲rejected。executor函數的返回值被忽略。
一個 Promise有如下幾種狀態:javascript

  • pending: 初始狀態,既不是成功,也不是失敗狀態。html

  • fulfilled: 意味着操做成功完成。java

  • rejected: 意味着操做失敗。ajax

使用promise

let status = 1;
// 判斷status是否爲1,是1的時候執行成功
let p1 = new Promise(function(resolve,reject){
    if(status==1){
        resolve({msg:"執行成功",status:"200"}); // 這裏傳遞給resolve的數據就是以後then中接受到的res
    }else{
        reject({msg:"執行失敗",status:"404"}); // 對應catch中的err
    }
});

p1.then(res=>{
    console.log(res);
}).catch(err=>{
    console.log(err);
})
複製代碼

Promise的一些注意點

Promise的理解

promise能夠當作是去肯德基買漢堡,先預約一個漢堡,而後收營員會給你一小票並向你承諾以後會給你一個漢堡(也可能漢堡買完了沒有漢堡)。從下單到得到漢堡的這個過程能夠當作是異步的操做,期間你能夠刷一下子手機,同時後廚在準備漢堡。有了漢堡以後吃漢堡(處理resolve),或者沒有漢堡了發生退款(處理reject)。
你在等待這個承諾的到來,一旦到來你就能夠開始吃漢堡或者沒有漢堡遺憾的退款。數組

  • new 出來的Promise對象就是收銀員的承諾
  • then 中的第一個回調就是收到漢堡最後吃漢堡的操做
  • then中的第二個回調就是沒有漢堡了退款的操做
  • Promise 構造函數是同步執行的,promise.then 中的函數是異步執行的

對於then的理解

then並非處理promise實例返回的resolve狀態值,resolvereject狀態的值都可以處理,第一個回調函數處理成功,第二個回調函數處理失敗,若是缺省第二個處理失敗的回調,則狀態爲rejectpromise傳遞到下一個鏈式調用。 promise

Promise實例狀態的變化

只有兩種變化過程,並且變化以後以後不會發生變化,會保持狀態的一致
只能從 _pending -> fulfilled 或者 從 pending -> rejected _一旦狀態發生變化就不會再發生改變,保持一致性。(你去買漢堡只可能有兩種狀態,買到漢堡和沒有買到,並且不可能在二者之間變化)異步

  • promise對此調用的結果保持一致,不會發生改變
  • 在Promise的構造調用的時候只能發生一次狀態轉變,一旦轉變以後不會發生變化
var promise = new Promise((resolve, reject) => {
    // 只能改變一次狀態
    resolve('1') // 改變狀態
    resolve('2') // 不生效
    resolve('3') // 不生效 
    console.log('4') //同步執行
  })
  // 屢次調用promise中的值不會發生變化
  promise.then((data) => {
    console.log('第一個then', data)
  })
  promise.then((data) => {
    console.log('第二個then', data)
  })
// 4
// 第一個then 1
// 第二個then 1
複製代碼

then,catch執行以後會返回一個新的promise

  • promise能夠鏈式調用不是由於使用return this, 而是在thencatch以後返回了一個promise
  • then或者catch返回當即值,則返回的promiseresolved狀態,至關於Promise.resolve(..)
  • 拋出現異常或者返回Promise.reject(..),則返回的promiserejected狀態
var promise = new Promise((resolve, reject) => {
    resolve('1')
  })
  promise.then((data) => {
    console.log(data) // 1
    return 2 // 做爲新的promise的resolve值返回
  }).then((data) => {
    // 這裏接收的是上一個then返回的新的promise的resolve狀態
    console.log(data) // 2
  })
  promise.then((data) => {
    // 能夠返回一個promise
    return Promise.reject('錯誤')
  }).catch((data) => {
    // catch接收上一個then返回的promise
    console.log(data) // 錯誤, 接收上一個鏈上的promise的resolve返回
  }).then((data) => {
    console.log(data) // undefined 前一個鏈上的promise沒有返回值
  })

    promise.then((data)=>{
      // 拋出錯誤
      throw new Error('出錯')
    }).catch((err) => {
      // 上一個promise返回的是reject, 內容是 拋出的error
      console.log(err)
    })

// 1
// 2
// Error: 出錯
// at promise.then (3.html:32)
// 錯誤
// undefined
複製代碼

異常處理的一些問題

  • 直接經過return new Error('錯誤')的方式返回異常不能被下一個catch捕獲到,這裏返回的promiseresolve狀態,會被傳遞下去被then捕獲,只有throw new Error()才能被下一個catch捕獲
var promise = new Promise((resolve, reject) => {
      resolve('1')
    })

    promise.then((data) => {
      return new Error('錯誤')
    }).catch((err) => {
      console.log('不會執行')
    }).then((data) => {
      console.log('打印以前返回的錯誤', data)
    })

    // 打印以前返回的錯誤 Error: 錯誤
    // at promise.then (4.html:16)
複製代碼
  • then(success, error) then能夠由兩個處理函數,第一個用來處理resolved狀態的promise返回值,第二個用來處理rejected狀態的promise返回值,這裏處理的是鏈式調用的返回的前一個promise
var promise = new Promise((resolve, reject) => {
    reject('錯誤')
  })

  promise.then((data)=>{
    console.log('不會執行,promise狀態是rejected')
  }, (err)=>{
    // 捕獲到錯誤
    console.log(err) // 錯誤
  }).catch((err) => {
    // 鏈式調用的前一個promise返回是一個resolve狀態
    console.log('不能捕獲到錯誤')
  })
複製代碼
  • then中沒有指定處理rejected狀態的函數時,錯誤狀態會一直傳遞下去直到被處理,要是沒有處理不會被window捕獲,直接控制檯報錯...
window.addEventListener('error', (e) => {
      console.log(e)
    })
    var promise = new Promise((resolve, reject) => {
      reject('錯誤')
    })
    promise.then((data)=>{
      console.log('未對錯誤處理')
    }).catch((err) => {
      // 執行
      console.log('上一個then中缺省處理錯誤的函數,錯誤會被封裝成新的promise向下傳遞', err)
    })
    promise.then((data)=>{
      console.log('不處理,也沒有後續,錯誤會被window捕捉到')
    })
複製代碼
  • .then 的第二個處理錯誤的函數捕獲不了第一個處理成功的函數拋出的錯誤,然後續的 .catch 能夠捕獲以前的錯誤
var promise = new Promise((resolve, rejected) => {
    resolve(1)
  })
  promise.then((data)=>{
    throw new Error('2')
  }, (err) => {
    console.log('不能捕獲,then中第一個成功回調返回的錯誤')
  }).catch((err)=>{
    console.log('能夠捕獲上一個then中成功或者錯誤處理函數中拋出的錯誤')
  })
複製代碼

Promise.resolve() 對於傳入值的處理

  • 傳入一個當即數 如 數字,字符串,則包裝成一個新的promise返回
  • 傳入的是一個真正的promise,則返回這個promise
  • 傳入的是一個thenable的值,則會解封到不是thenable爲止
// 傳入當即數
Promise.resolve(1).then((data)=>{console.log(data)}) // 1

// 傳入promise對象
var p1 = new Promise((resolve,reject) => {
  resolve(2)
})
var p2 = Promise.resolve(p1)
console.log(p1 === p2) // true 返回同一個

// thenable
var o = {
  then:function(cb,err){
    console.log('then函數')
    cb(3)
  }
}
Promise.resolve(o).then((data)=>{console.log(data)}) // then函數 3
複製代碼

判斷一個函數是否是thenable函數

if(!!p 
   &&
   (typeof p === 'object' || typeof p === 'function')
   &&
   (p.then && typeof p.then === 'function')
  ) { console.log(true)} else {
  console.log('false)
}
複製代碼

用來控制請求的執行順序

Promise.all方法常被用於處理多個promise對象的狀態集合。輸入是一個由promise對象組成的數組,全部的promise對象都成功的時候纔會觸發成功,一旦有任何一個iterable裏面的promise對象失敗則當即觸發該promise對象的失敗。這個新的promise對象在觸發成功狀態之後,會把一個包含iterable裏全部promise返回值的數組做爲成功回調的返回值,順序跟iterable的順序保持一致;若是這個新的promise對象觸發了失敗狀態,它會把iterable裏第一個觸發失敗的promise對象的錯誤信息做爲它的失敗錯誤信息。ui

這時候能夠這樣,將一組ajax請求封裝成一組promise對象傳入Promise.all,返回結果也是有序的,再對這個有序的promise對象進行處理this

用來控制請求超時

Promise.raceiterable參數裏的任意一個子promise被成功或失敗後,父promise立刻也會用子promise的成功返回值或失敗詳情做爲參數調用父promise綁定的相應句柄,並返回該promise對象。(任意一個成功或者失敗就觸發)


此時能夠構造一個 定時器任務和一個ajax請求,封裝成promise對象傳入Promise.race,若是定時器的結果先返回,則請求超時

相關文章
相關標籤/搜索