你可能忽略的 async/await 問題

0-cover.png

async/await 你們確定都用過,在處理異步操做的時候真的是很方便。json

若是有還不熟悉的小夥伴能夠看筆者以前的文章:segmentfault

帶你理解 async/awaitapi

那今天主要講一些在使用 async/await 時容易忽略和犯錯的地方。dom

一個例子

下面是一個常見的 Vue 代碼片斷:異步

async initStore(query) {
    await this.getConfig();
    await this.getUser();
    await this.checkRussianContext(query);

    await this.getBasket(this.$store.state.config.selectedCurrency),

    await this.$store.dispatch('options/fetchOptions', {
      basket : this.$store.state.basket,
    });
 },

上面的代碼中,每一行都會 等待上一行的結果返回後纔會執行。好比其中的 getUser 會等待 getConfig 數據返回以後纔會執行。async

當看到這段代碼時,腦子裏應該注意到如下幾點:工具

  • 若是某一行的執行不須要上面一行的數據怎麼辦?爲何阻塞代碼使整個應用程序變慢呢?
  • 咱們可不可讓全部不相關的方法一塊兒執行?好比使用 Promise.all
  • 可否讓相關的方法使用 then 進行鏈式調用來避免阻塞剩餘代碼?

本篇文章的重點就是經過分析 async/await 可能引起的問題,幫你找到 代碼的壞味道fetch

無關的請求請並行執行

讓咱們來看一些具體的數據下的狀況。this

下面是示例代碼:spa

const getUserData = async () => {
  // 獲取一張隨機的狗狗圖片做爲頭像
  const res = await fetch('https://dog.ceo/api/breeds/image/random')
  const { message } = await res.json()

  // 獲取隨機生成的用戶信息
  const user = await fetch('https://randomuser.me/api/')
  const { results } = await user.json()

  // ...
}

上面的代碼在 fast 3G (使用 Chrome 開發者工具)下執行 100 次,平均執行時間爲 1231.10ms

可是很顯然,第二個請求並不須要第一個請求的結果,因此咱們修改爲如下代碼並執行 100 次:

const getUserDataFaster = async () => {
  // 兩個請求並行執行
  const [res, user] = await Promise.all([
    fetch('https://dog.ceo/api/breeds/image/random'), 
    fetch('https://randomuser.me/api/')
  ])
  const [{ message }, { results }] = await Promise.all([res.json(), user.json()])

  // ...
}

咱們獲得的平均執行時間爲 612.50ms,幾乎節省了一半時間。

劃重點:儘量地把查詢請求並行執行。

能夠用這個 codepen 中的代碼體驗

無關的代碼你沒必要等

再來例子:

async initStore(query) {
   await Promise.all([
     this.getConfig(),
     this.getUser(),
     this.checkRussianContext(query)
   ])

   await this.getBasket(this.$store.state.config.selectedCurrency),

   await this.$store.dispatch('options/fetchOptions', {
     basket : this.$store.state.basket,
   });

   await initBooking()
},

前面的 3 個請求是並行執行的,而下一段代碼依賴了前面獲取的數據,因此須要在其後執行,可是你有沒有發現其中的問題?

initBooking 這個小可憐只能等到 getBasketfetchOptions 完成以後才能執行,儘管它不須要這兩個方法的任何數據。

一個簡單的解決辦法是將 await 換成 .then 來使用:

關於這個用法能夠看開頭的另外一篇文章
async initStore(query) {
  await Promise.all([
    this.getConfig(),
    this.getUser(),
    this.checkRussianContext(query)
  ])

  this.getBasket(this.$store.state.config.selectedCurrency).then(async () => {
    await this.$store.dispatch('options/fetchOptions', {
      basket : this.$store.state.basket,
    });
  })   

  await initBooking()
},

這樣的話,getBasketinitBooking 均可以並行執行了。

結論

async/await 是 JavaScript 中的一個很是棒的特性,咱們在享受它們便利寫法的同時,也要清楚它們可能引起的問題。有機會審查一下你的代碼,看有沒有能夠並行運行的代碼塊吧~

Thanks for reading~

參考連接


本文首發於公衆號:碼力全開(codingonfire)

本文隨意轉載哈,註明原文連接便可,公號文章轉載聯繫我開白名單就好~

codingonfire.jpg

相關文章
相關標籤/搜索