潛入理解ES6-Promise用法小結

寫在前面

感性上的理解:Promise咱們能夠理解爲作了一個保證,作了這個保證無論成功resolve()仍是失敗reject()都會告知咱們———返回帶有最終結果或者拒絕緣由 的Promisejavascript

Promise的三種狀態

  • 掛起
  • 已成功
  • 已完成

其中後兩種都是異步操做完成後的狀態java

Promise作保證

Promise對象用於表示一個異步操做的最終狀態(完成或失敗),以及其返回的值。ios

MDN對Promise的定義如上,能夠理解爲此對象作了一些保證,告知咱們異步操做的狀態。具體以下:axios

  • 當前事件隊列執行完成以後,再調用回調函數
  • 回調函數是經過then添加的
  • 添加多個then,能夠添加多個回調函數,依次執行

Promise鏈式調用

存在的需求:有時候咱們須要連續調用多個異步操做,每個操做都創建在獲得上一部結果以後。之前有回調函數,這樣會容易形成回調地獄。而採用Promise以後,每一步操做成功/失敗以後都會帶上其結果,執行下一個操做。api

// 回調地獄
doSomething(function(result) {
  doSomethingElse(result, function(newResult) {
    doThirdThing(newResult, function(finalResult) {
        console.log('Got the final result: ' + finalResult);
    }, failureCallback);
  }, failureCallback);
}, failureCallback);

//採用Promise鏈式調用以後
doSomething().then(function(result) {
  return doSomethingElse(result);
})
.then(function(newResult) {
  return doThirdThing(newResult);
})
.then(function(finalResult) {
  console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);
複製代碼

錯誤處理

在上面的代碼段1中,有三個錯誤回調函數。而在Promise鏈式調用中,只在結尾加上錯誤處理回調便可,當有錯誤拋出時,會返回一個帶有錯誤緣由的Promise到下一級catch,直到最底端catch函數。數組

// 依次輸出: Initial Do that
new Promise((resolve, reject) => {
    console.log('Initial');
    resolve();
})
.then(() => {
    throw new Error('Something failed');
    console.log('Do this');
})
.then(() => {
    console.log('Do this whatever happened before');
})
.catch(() => {
    console.log('Do that');
})
複製代碼

此外,若是中途捕獲了異常,依然能夠接着then下去:promise

/* * 依次輸出: * Initial * Do that * Do this whatever happened before */
new Promise((resolve, reject) => {
    console.log('Initial');
    resolve();
})
.then(() => {
    throw new Error('Something failed');
    console.log('Do this');
})
.catch(() => {
    console.log('Do that');
})
.then(() => {
    console.log('Do this whatever happened before');
})
複製代碼

緣由在於catch(failureCallback)自己是then(null, failureCallback)的縮略形式,也是返回帶有當前狀態的Promise。下面這樣我們還能捕獲到異常信息:app

/* * 依次輸出: * Initial * Something failed * Do that * Do this whatever happened before */
new Promise((resolve, reject) => {
    console.log('Initial');
    resolve();
})
.then(() => {
    throw new Error('Something failed');
    console.log('Do this');
})
.catch((e) => {
    console.log(e.message)
    console.log('Do that');
})
.then(() => {
    console.log('Do this whatever happened before');
})
複製代碼

使用async/await語法糖

一個栗子異步

// 使用Promise
doSth()
    .then(res => doSthElse(res))
    .then(newRes => doThirdTh(newRes))
    .then(finalRes => {
        console.log(`finalResult is ${finalRes}`)
    })
// 使用async/await將異步代碼寫成同步樣式
async funtion foo () {
    let res = await doSth()
    let newRes = await doSthElse(res)
    let finalRes = await doThirdTh(newRes)
    console.log(`finalResult is ${finalRes}`)
}
複製代碼

Promise.resolve()、Promise.reject()妙用

使用這兩種靜態方法能夠建立resolve或reject的保證,栗子以下:async

getRecommend () {
    let today = new Date()
    let date = new Date(today.getFullYear(), today.getMonth() + 1, today.getDate(), 9)
    
    return axios.get(`/api/getRecommend?date=${Number(date)}`
    ).then(response => {
      return Promise.resolve(response.data)
    }).catch(err => {
      console.log(err)
    })
}
複製代碼

當使用axios成功請求/api/getRecommend時,axios返回一個Promise對象,由於getRecommend()是要export出去的,這裏直接返回一個狀態完成的Promise,調用getRecommend()時,若是成功響應直接能夠recommend.getRecommend().then(res => {})獲取響應結果。

Promise.all()、Promise.race()並行執行多個Promise對象

  • Promise.all()是全部Promise對象狀態都是‘已成功’才結束
  • Promise.race()是有一個Promise對象狀態‘已成功’就結束

Promise串行執行

Promise鏈式調用

下面這個累加例子很好地顯示了Promise之間傳值計算:

// 第一步,執行XXX操做,保證了***結果
let step1 = function () {
  let val = 1
  console.log(`this is step1 , the value is ${val}`)
  // 拒絕的狀況,balalala...
  if (val > 0){
    return Promise.resolve(val)
  }
  return Promise.reject(val)
}
// 第二步,執行XXX操做,保證了***結果
let step2 = function (val) {
  val += 1
  console.log(`this is step2 , the value is ${val}`)
  return Promise.resolve(val)
}
// 第三步,執行XXX操做,保證了***結果
let step3 = function (val) {
  val += 1
  console.log(`this is step3 , the value is ${val}`)
  return Promise.resolve(val)
}

step1().then((val)=>{
  return step2(val)
}).then((val)=>{
  return step3(val)
}).then((val)=>{
  console.log(`finally, the value is ${val}`)
})

// 輸出結果
this is step1 , the value is 1
this is step2 , the value is 2
this is step3 , the value is 3
複製代碼

aysnc/await

再用async/await語法糖實現一遍累加

// 在這裏咱們把每一步操做看做異步的
function step21() {
  let val = 1
  console.log(`this is step1 , the value is ${val}`)
  return val
}

function step22(val) {
  val += 1
  console.log(`this is step2 , the value is ${val}`)
  return val
}

function step23(val) {
  val += 1
  console.log(`this is step3 , the value is ${val}`)
  return val
}

(async () => {
  // await使用必須在async函數內
  let val = await step21()
  val = await step22(val)
  val = await step23(val)
})()

// 輸出結果
this is step1 , the value is 1
this is step2 , the value is 2
this is step3 , the value is 3
複製代碼

Promise數組串行

使用數組的reduce()方法依次執行,

// 第一步,執行XXX操做,保證了***結果
let step1 = function () {
  let val = 1
  console.log(`this is step1 , the value is ${val}`)
  // 拒絕的狀況,balalala...
  if (val > 0){
    return Promise.resolve(val)
  }
  return Promise.reject(val)
}
// 第二步,執行XXX操做,保證了***結果
let step2 = function (val) {
  val += 1
  console.log(`this is step2 , the value is ${val}`)
  return Promise.resolve(val)
}
// 第三步,執行XXX操做,保證了***結果
let step3 = function (val) {
  val += 1
  console.log(`this is step3 , the value is ${val}`)
  return Promise.resolve(val)
}

let steps = [step1, step2, step3]
steps.reduce((promise, fn, index)=>{
  console.log(index)
  return promise.then((val)=>{
    return fn(val)
  })
  // reduce函數init參數
}, Promise.resolve())

// 輸出結果
this is step1 , the value is 1
this is step2 , the value is 2
this is step3 , the value is 3
複製代碼

async/await數組串行

暫時只想到數組的方法,使用Array.prptotype.reduce()爲解決,仍是沒有深刻了解reduce()是如何實現的

async function foo () {
  let val
  for (let i = 0; i < steps.length; i++) {
    if (i===0) {
      val = await steps[i]()
    }else {
      val = await steps[i](val)
    }
  }
}
foo()
複製代碼
相關文章
相關標籤/搜索