ES7-async/await學習

前言

網上有不少關於async/await的學習文章,我也是經過這些文章學習瞭解async的,可是不總結一下,總以爲沒有真正學到。若有錯誤的地方還請多多指出。javascript

什麼是async/await

有人說它是JS編程異步的「終極解決方案」,終不終極不知道,事物老是在發展的嘛,可是能被冠上這麼個頭銜也絕非等閒之輩了😊。async是「異步的」,await是「等待」,async是形容詞,await是動詞,那麼async形容的函數告訴別人這是個包含異步的「異步的函數」,而await要等待某個東西的到來。a/a給了咱們從新使用try catch的權力,而且規定await必須寫在async形容的函數中。使用a/a要對Promise有所理解,那還要從回調提及。html

回調函數

JS是一根筋的(單線程),一次只執行一個任務,後面的要等前面的完成才行, 若是某個任務要佔用很長時間,那麼後面的任務就都要等着。因此java

JS將任務的執行模式分紅兩種:同步(Synchronous)和異步(Asynchronous)。 地址

回調函數就是「異步「的方法之一。你們對回調很熟啦,回調會產生一個問題-回調地獄,兩層回調還好,三層彷佛也能夠接受,硬着頭皮四層也行,五層要不要寫,咬咬牙六層就行了。。。最後,一首楊宗緯的洋蔥送給本身。一層一層剝開回調,找到最終的小可愛。
好比下面的栗子:編程

a1(function(res) {
  d2(res, function(newRes) {
    a3(newRes, function(finalRes) {
      console.log('a3: ' + finalRes);
    }, a1FCb);
  }, a2FailCb);
}, a3FailCb);

另外,當年我還年輕的時候,初試回調,在回調函數中花樣百出的嘗試return,在回調外面也取不到return的值,大概下面這個樣子promise

var a = ''
function fool(){
  setTimeout(() => {
     return 'hi'// 或者
  }, 1000);
}
a = fool()
console.log(a) //undefined 由於setTimeout異步執行,a=fool()執行在timeout以前,而此時的fool()並內有return任何東西

回調讓咱們失去了直接「使用return」的方式,那來看看Promise。異步

Promise

顧名思義,promise是承諾的意思,承諾在將來是能夠兌現的,promise能夠有效的解決回調地獄,並且給了咱們使用return的權力。只不過它的return還是一個承諾。對於promise的學習可參考promise MDNPromise MDNasync

一個 Promise有如下幾種狀態:
pending: 初始狀態,既不是成功,也不是失敗狀態。
fulfilled: 意味着操做成功完成。
rejected: 意味着操做失敗。

以下一個利用Promise構造函數聲明的實例ide

new Promise(function(resolve,reject){//...})

resolve 和 reject 函數被調用時,分別將promise的狀態改成fulfilled(完成)或rejected(失敗),這兩個狀態不能同時出現,兩個狀態完成時,分別調用promise的then方法中對應的onfulfilled 和onrejected 函數。舉個例子:函數

function a(val){
  return new Promise(function(resolve,reject){
    if(val === 1){
      resolve(val)
    } else {
      reject('bad val')
    }
  })  
}

函數a接收一個參數,返回一個promise實例,當參數是指望的1時,表示操做成功,其餘值被認爲操做失敗。那麼若是執行如下操做學習

a(1).then(function(res){
  console.log('onfulfilled '+ res)
},function(errMsg){
  console.log('onrejected '+ errMsg)
})
//會log出'onfulfilled 1'

該操做a(1)會調用函數a內部promise實例的resolve函數,把該promise的狀態變成了fulfilled,因此以後會調用then函數裏onfulfilled的函數。

另外,對於操做失敗的狀態,除了在then中指定對應的onreject函數外,也可使用catch,使用catch的好處在於,若是是多個異步操做,只須要指定一個catch便可,不用爲每層then都指定一個onreject函數。舉個例子:

有以下三層回調:

fun1(function(res1){
  fun2(function(res1){
    var res2 = res1 + 'hello'
    fun3(function(res2){
      var res3 = res2 + 'hi'
      console.log('the final res ' + res3)
    },fun3FailCb)
  },fun2FailCb)
},fun1FailCb)

改爲promise寫法後:

fun1()
  .then(function(res1){
    return fun2(res1+'hello')
  })
  .then(function(res2){
    return fun3(res2+'hi')
  })
  .then(function(res3){
    console.log('the final res' + res3)
  })
  .catch(function(err){
    console.log('something bad occured')
  })

清爽不少。then的鏈寫多了,看起來也很煩啊,有沒有更簡潔的方法?有!

async/await

async/await是一個語法糖,他和promise關係緊密,可參考async MDN

當調用一個 async 函數時,會返回一個 Promise 對象。當這個 async 函數返回一個值時,Promise 的 resolve 方法會負責傳遞這個值;當 async 函數拋出異常時,Promise 的 reject 方法也會傳遞這個異常值。

回到開篇說的,async所形容的函數告訴別人這是個包含異步的「異步的函數」,也就是async的函數會返回一個promise (同步的代碼也不要緊,只不過沒啥意義了)。await要等的就是其餘async函數返回的這個promise,promise狀態成功,await等到的是resolve中的值,promise狀態失敗,await等到的是reject中的錯誤信息,換句話說,被try/catch中的catch到了。舉個例子:

async function f1(val){
  if(val === 1){
    return val
  } else {
    throw 'not 1'
  }
} //調用f1(val)時,會自動返回一個包裝好的promise
async function f2(val2){
 try{
   var res1 = await f1(val2)
   console.log('res1' , res1)
  }catch(errmsg){
   console.log('catch ', errmsg)
  }  
}

分別執行f2(1)和f2(3)查看log結果。

改寫前面的三層回調

async function fun1(){
  return res1
}
async function fun2(val){
  return val + 'hello'
}

async function fun3(val){
  return val + 'hi'
}

async function fun4(){
 try{
   var res1 = await fun1()
   var res2 = await fun2(res1)
   var res3 = await fun3(res2)
   console.log('the final res ', res3)
   // other operation with res3/res2/res1...
 }catch(err){
   console.log('something bad')
 }
  
}

至關清爽。在async內,await會阻塞後面的程序執行,直到promise的狀態完成(成功或失敗)。

相關文章
相關標籤/搜索