1. 程式人生 > 其它 >前端開發:Async/Await的使用心得

前端開發:Async/Await的使用心得

接著三掌櫃的上一篇關於Promise的使用的博文來繼續講,前端處理非同步回撥操作用到的方法之一:Async/Await。可以說Async/Await是Promise的升級版,而且應用了Async/Await的非同步請求的情況下,可以讓程式碼看起來像同步方式呼叫解決非同步回撥。

在ES7之前,瞭解到Promise是ES6為了解決非同步回撥而產生的解決方案,避免出現回撥地獄(Callback Hell),那麼ES7為什麼又提出了新的Async/Await標準?問題答案就是:Promise雖然解決了非同步巢狀的怪圈,使用表達清晰的鏈式表達;但是如果在實際開發過程中有些地方有大量的非同步請求的時候,而且流程複雜巢狀的情況下,檢查相關程式碼會發現一個比較尷尬。

一、Async/Await是什麼?

Async/Await是基於Promise而來的,Async/Await是相互依存的,缺一不可,它們的出現就是為了Promise而來,也算是Promise的進化改良版,為的就是解決文章開始說的如果出現大量複雜巢狀不易讀的Promise非同步問題。

1、Async/Await基本含義

①Async/Await是基於Promise實現的,是寫非同步程式碼的新方式,它們不能用於普通的回撥函式;

②Async/Await也是非阻塞的;

③Async/Await的寫法使得非同步程式碼看起來像同步程式碼,簡潔、便於讀取。

2、Async/Await的語法

async必須宣告的是一個function函式,await就必須是在async宣告的函式內部使用,這是一個固定搭配,任何一種不符合這兩個條件,程式就會報錯,具體舉例項來直觀看一下:

let data = 'data'

a = async function () {

  const b = function () {

    await data

  }

}

二、Async/Awaitd的本質

1、 Async的本質

async是對generator的再一次語法糖封裝,幫助實現了生成器的呼叫,使語句更貼近同步程式碼的表達方式,可以將async函式看做是多個非同步操作封裝的 promise物件。

async宣告的函式的返回其實就是一個Promise,也就是說只要宣告的函式是async,不管內部怎麼處理,它返回的一定是一個Promise,舉個例子如下所示:

(async function () {

  return 'Promis+++‘

})() // 返回的是Promise+++

2、 Awaitd的本質

await的本質其實是可以提供等同於“同步效果”的等待非同步返回能力的語法糖,也就是then的語法糖。如果想使用await來執行一個非同步操作,那麼其呼叫函式必須使用async來宣告。

await能返回一個Promise物件,也能返回一個值。若await返回的是Promise物件,那麼還可以繼續給await的返回值使用then函式。舉個例項看一下:

const a = async ()=>{

  let message = '宣告值111’

  let result = await message;

  console.log('由於上面的程式還沒執行完,“等待一會”');

  return result

}

a().then(result=>{

 console.log('輸出',result);

})

三、 Async/Await的優勢

為什麼說Async/Awaitd比Promise更勝一籌?具體原因如下所示。

1、 簡潔明瞭

根據上述關於Async/Awaitd的例項可以看到,Async/Awaitd的寫法很簡單,相比Promise的寫法,不用寫.then,不用寫匿名函式處理Promise的resolve值,也不用定義多餘的data變數,更避免了巢狀程式碼的操作,大大省去了很多程式碼行,使得處理非同步操作的程式碼簡潔明瞭,方便查閱和精準定位。

2、 錯誤處理的方式

Async/Await可以讓try/catch同時處理同步和非同步的錯誤,而且在Promise中try/catch不能處理JSON.parse的錯誤,在Promise中需要使用.catch,但是錯誤處理的那坨程式碼會非常冗餘,要知道實際開發過程中程式碼會比理論上的情況會更復雜。

通過使用Async/Await,try/catch能處理JSON.parse的錯誤,具體例項如下所示:

 const request = async () => {

    try {

      const data = JSON.parse(await getJSON())

      console.log(data)

    } catch (err) {

      console.log(err)

    }

}

3、 條件語句

通過使用Async/Await,可以使得條件語句寫法簡潔又可以提高程式碼可讀性,這裡就不再舉對比的例子,只舉一個Async/Await的使用例項來說:

const request = async () => {

 const data = await getJSON()

 if (data.anotherRequest) {

  const moreData = await anotherRequest(data);

  console.log(moreData)

  return moreData

 } else {

  console.log(data)

  return data  

 }

}

4、 中間值

在實際開發過程中會遇到這種場景:呼叫promise1,使用promise1返回的結果再去呼叫promise2,然後使用兩者的結果去呼叫promise3。在沒有使用Async/Await之前的寫法,應該是這樣的:

const request = () => {

  eturn promise1()

     .then(value1 => {

    return promise2(value1)

    .then(value2 => {    

       return promise3(value1, value2)

    })

  })

}

使用了Async/Await的寫法之後,是這樣的:

const request = async () => {

 const value1 = await promise1()

 const value2 = await promise2(value1)

 return promise3(value1, value2)

}

通過上述兩個寫法,直觀的看出來使用Async/Await之後會使得程式碼變得非常整潔簡單,直觀,高可讀性。

5、 錯誤棧對比

如果例項中呼叫多個Promise,其中的一個Promise出現錯誤,Promise鏈中返回的錯誤棧沒有顯示具體的錯誤發生的位置資訊,這就造成排查錯誤的耗時時長和解決的難度,甚至會起到反作用,假設錯誤棧的唯一函式名為errorPromise,但是它和錯誤沒有直接關係。如果使用了Async/Await之後,錯誤棧會直接指向錯誤所在的函式,這樣更清晰直觀的方便排查問題所在,尤其是在檢視分析錯誤日誌的時候非常有效有用。

6、 除錯

通過上面描述的Async/Await優點中,一直在反覆強調Async/Await會使得程式碼簡潔明瞭,其實在除錯過程中,Async/Await也可以使得程式碼除錯起來很輕鬆簡單,相對於Promise來講,不用再寫太多箭頭函式,可以直接像除錯同步程式碼一樣單步走,跳過await語句。

7、 中斷/終止程式

首先要明確知道,Promise自身是不能終止的,Promise本身只是一個狀態機,儲存了三種狀態,一旦進行發出請求,就必須要閉環,無法進行取消操作,就算是在前面講到的pending狀態,也只是一個掛起請求的狀態,但不是取消。

但是使用Async/Await的時候,想要終止程式就很簡單,那是因為Async/Await語義化很明顯,和一般的function的寫法類似,想要終端程式的時候,直接return一個值(“”、null、false等)就可以了,實際上就是直接返回一個Promise。具體例項如下所示:

let count = 3;

const a = async ()=>{

 const result = await delay(2000);

 const result1 = await delaySecond(count);

 if (count > 2) {

   return '';

  // return false;

  // return null;

 }

 console.log(await delay(2000));

 console.log(‘結束’);

};

a().then(result=>{

 console.log(result);

})

.catch(err=>{

 console.log(err);

})

async函式本質就是返回一個Promise。

四、實際開發過程中非同步操作需要注意的事項

Async/Await使用for迴圈獲取資料(序列)

根據上面Promise的for迴圈獲取資料來做對比,直接使用上述例項的場景,來看看Async/Await的寫法,具體操作如下所示:

(async ()=>{

  array = [timeout(2000), timeout(1000), timeout(1000)]

  for (var i=0; i < array.length; i++) {

    result = await array[i]();

    console.log(result);

  }

})()

通過對比,在這裡還要誇一下Async/Await,直觀的可以看到同樣的需求,使用Async/Await來實現是不是非常的方便和簡潔。

以上就是本章全部內容,歡迎關注三掌櫃的微信公眾號“程式猿by三掌櫃”,三掌櫃的新浪微博“三掌櫃666”,歡迎關注!

https://www.361zimeiti.cn/402665.html
https://www.361zimeiti.cn/402675.html