深刻理解await與async

1-1.await

  • await的意思就是等待。它後面能夠跟一個表達式。若是是值(如字符串、數字、普通對象等等)的話,返回值就是自己的值。
  • 不過最經常使用的是後面跟一個promise對象。await會等待這個promise的狀態由pending轉爲fulfilled或者rejected。在此期間它會阻塞,延遲執行await語句後面的語句。
  • 若是promise對象的結果是resolve,它會將resolve的值,做爲await表達式的運算結果。
語法糖本質

​ 其實awaitasync自己就是promise化編程的一種語法糖。對比一下兩種寫法。編程

// 異步promise化的函數--模擬請求後端接口
function asyncFn () {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      if (true) {
        console.log('resolve console')
        resolve('resolve return')
      } else {
        reject('reject return')
      }
    }, 2000)
  })
}

// promise
asyncFn().then((res) => {
  console.log(res)
}, (err) => {
  console.log(err)
})

// await
try {
  var res = await asyncFn()
  console.log(res)
} catch(err) {
  console.log(err)
}

// 若是有第二次請求的話,promise須要在then方法繼續調用,再用then接受,過多的嵌套依然會增長閱讀難度。而await async只須要像寫同步代碼同樣繼續書寫就能夠,它是解決異步編程回調地獄的終極手段。
例一
// ps:因爲js自己如今已經限制了await必須用在async函數中,不然會報錯。因此請將下面的複製粘貼到瀏覽器控制檯查看結果

function asyncFn () {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      if (true) {
        console.log('resolve console')
        resolve('resolve return')
      } else {
        reject('reject return')
      }
    }, 2000)
  })
}

var value1 = await asyncFn()
var value2 = await 'plain text'
console.log(value1)
console.log(value2)

//瀏覽器會依次打印 ‘resolve console’ ‘resolve return’ ‘plain text’
例二

若是你對結果有疑問,能夠將asyncFn前面的await去掉,再在瀏覽器控制檯執行一次。後端

這兩次對比一下,會發現第二次的resolve console是最後打印出來的,而第一次的是第一個打印的。promise

根本緣由就是第一次代碼中await阻塞了後面語句的執行,等待promise肯定結果後繼續執行後面語句。瀏覽器

例三

根據前兩例可想而知,若是兩個await的後面跟着的都是promise對象。那麼第二個await等待的時間是它自己等待的時間加上第一個await等待的時間異步

function asyncFn1 () {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      if (true) {
        console.log('resolve console1')
        resolve('resolve return1')
      } else {
        reject('reject return1')
      }
    }, 2000)
  })
}

function asyncFn2 () {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      if (true) {
        console.log('resolve console2')
        resolve('resolve return2')
      } else {
        reject('reject return2')
      }
    }, 2000)
  })
}

var value1 = await asyncFn1()
var value2 = await asyncFn2()

// 複製並執行,會發現2s後打印了‘resolve console1’,4s後打印了‘resolve console2’
思考
// 已經知道了await會阻塞代碼的執行,若是咱們在實際開發中有這樣的代碼。

function fn () {
  // 假設request是請求後端接口
  var value = await request()
  console.log(value)
  // ...
}
fn()

var arr = []
arr.push('1')
// ...其餘不依賴後端接口邏輯

​ 在fn調用後,因爲await的阻塞,必然會影響到下面的邏輯。在實際開發中,若是後端接口5s才響應,那麼下面的代碼就須要等待5s。顯然這是不合理的,爲了解決這種現象,就須要async聲明。async

1-2.async

​ 以前咱們知道了await會阻塞代碼的執行。而解決這個弊端的手段就是async聲明。異步編程

async function asyncFn () {
  return 'async'
}
console.log(asyncFn())

​ 控制檯打印一下,會發現打印的是一個promise對象。並且是Promise.resolve對象。resolve的值就是asyncFn的函數返回值async函數

​ 若是函數沒有返回值的話,它天然返回的會是Promise.resolve(undefined)code

其實之因此async聲明能解決await的阻塞問題,就是由於async聲明將函數做了一層promise包裝,這樣內部的異步操做其實就是由pending轉爲resolve或者reject的過程。這樣函數自己就可以隨意調用,函數內部的await也不會再影響到函數外部的代碼執行。對象

相關文章
相關標籤/搜索