深入理解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是最后打印出來的,而第一次的是第一個打印的。

根本原因就是第一次代碼中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聲明。

1-2.async

​ 之前我們知道了await會阻塞代碼的執行。而解決這個弊端的手段就是async聲明。

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

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

​ 如果函數沒有返回值的話,它自然返回的會是Promise.resolve(undefined)

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM