1. 程式人生 > >JavaScript async / await:好處、坑和正確用法

JavaScript async / await:好處、坑和正確用法

async/await給我們帶來的最重要的好處是同步程式設計風格。我們來看一個例子吧。

很明顯,async/await版本比promise版本更容易理解。如果忽略await關鍵字,程式碼看起來就像任何其他同步語言,如Python。

好的一面不僅是可讀性,async/await有本地瀏覽器支援。截至今天,所有主流瀏覽器 檢視都完全支援非同步功能。

本機支援意味著您不必轉換程式碼。更重要的是,它有助於除錯。當您在函式入口設定斷點並跳過await行時,您將看到偵錯程式在bookModel.fetchAll()執行期間暫停一段時間,然後移動到下一 行.filter!這比promise

情況要容易得多,在promise情況下你必須在.filter行設定另一個斷點 。

另一個不太明顯的好處是async關鍵字。它宣告getBooksByAuthorWithAwait()函式返回值確保是一個promise,以便呼叫者可以安全呼叫getBooksByAuthorWithAwait().then(...)await getBooksByAuthorWithAwait()。看看下面的程式碼(不好的做法!):

在上面的程式碼中,getBooksByAuthorWithPromise可以返回一個promise(正常情況)或一個null值(例外情況),在這種情況下,呼叫者不能安全地呼叫.then()

。通過async宣告,這種返回null的情況將不可能出現。

Async/await可能會產生誤導

有些文章將async/awaitPromise進行比較,並聲稱它是JavaScript非同步程式設計演變的下一代,我表示不同意。Async/await是一種改進,但它只不過是一種語法糖,它不會完全改變我們的程式設計風格。

從本質上講,await函式仍然是promise。在正確使用await函式之前,您必須瞭解promises,還有就是,大多數情況下您需要同時使用promises和非同步函式。

考慮上面示例中的getBooksByAuthorWithAwait()getBooksByAuthorWithPromises()

函式。請注意,它們不僅在功能上相同,而且具有完全相同的介面。

如果直接呼叫getBooksByAuthorWithAwait(),這意味著將返回一個promise

嗯,這並不是壞事。只是await這個名稱讓人感覺“哦,這可以將非同步函式轉換為同步函式”,這實際上是錯誤的。

Async/await的坑

那麼使用async/await時會出現什麼錯誤?以下一些常見的情況。

太順序了

雖然await可以使您的程式碼看起來像同步,但請記住它們仍然是非同步的,必須注意避免過於順序。

此程式碼看起來邏輯正確。但這是錯誤的。

  1. await bookModel.fetchAll()將等到fetchAll()返回。
  2. 然後await authorModel.fetch(authorId)將被呼叫。 請注意authorModel.fetch(authorId)它不依賴於bookModel.fetchAll()的結果,實際上它們可以並行呼叫!但是,通過await在這裡使用,這兩個呼叫變為順序,並且總執行時間將比並行版本長得多。

這是正確的方法:

或者更糟糕的是,如果你想逐個獲取一個列表的項,必須依賴promise

簡單地說,您仍然需要非同步考慮工作流,然後嘗試同步編寫程式碼await。在複雜的工作流程中,直接使用promises可能更容易。

錯誤處理

使用promises,非同步函式有兩個可能的返回值:已解析的值和被拒絕的值。我們可以.then()用於正常情況,.catch()用於特殊情況。但是,async/await錯誤處理可能會很棘手。

try…catch

最標準的(我推薦的)方法是使用try...catch語句。當一個await呼叫時,任何被拒絕的值都將作為異常丟擲。這是一個例子:

catch的錯誤正是被拒絕的值。在我們發現異常後,有幾種方法來處理它:

  1. 處理異常,並返回正常值。(不在catch塊中使用任何return語句,這等同於使用return undefined,也是正常值。)
  2. 丟擲它,如果你想讓呼叫者處理它。可以直接丟擲普通的錯誤物件throw error,這在promise鏈中允許使用async getBooksByAuthorWithAwait()函式(即仍然可以像這樣呼叫它getBooksByAuthorWithAwait().then(...).catch(error => ...)); 或者可以使用Error物件包裝錯誤,例如throw new Error(error) ,當控制檯中顯示此錯誤時,將提供完整的堆疊跟蹤。
  3. 拒絕它,就像return Promise.reject(error) 。這相當於throw error不推薦。

使用try...catch的好處是

  • 簡單,傳統。只要您有Java或C++等其他語言的經驗,就不會有任何困難。
  • 如果不需要每步執行錯誤處理,仍然可以在一個try...catch塊中包裝多個await呼叫在一個位置處理錯誤。

這種方法也存在一個缺陷。由於try...catch將捕獲塊中的每個異常,因此將會捕獲一些通常不會被promises捕獲的異常。想想這個例子:

執行此程式碼,您將在控制檯中收到ReferenceError: cb is not defined錯誤。錯誤是由console.log()輸出而不是JavaScript本身。有時這可能是致命的。如果BookModel被深深地包含在一系列函式呼叫中,並且其中一個呼叫吞噬了錯誤,那麼找到這樣的未定義錯誤將非常困難。

使函式返回兩個值

簡言之,您可以使用這樣的await函式:

我個人不喜歡這種方法,因為它將Go風格帶入JavaScript,感覺不自然,但在某些情況下,這可能非常有用。

使用.catch

我們將在這裡介紹的最後一種方法是繼續使用 .catch()

回想一下await的功能:它將等待promise完成其工作。再回想一下,promise.catch()也將是一個promise,所以我們可以像這樣編寫錯誤處理:

這種方法有兩個小問題:

  1. 它是promisesawait函式的混合體。您仍然需要了解promises的工作原理。
  2. 錯誤處理在正常路徑之前進行,這樣不直觀。

結論

ES7引入的關鍵字async/await肯定是對JavaScript非同步程式設計的改進。它可以使程式碼更容易閱讀和除錯。然而,為了正確使用它們,必須完全理解promise,因為它們只不過是語法糖,而潛在的技術仍然是promise

1、具有1-5工作經驗的,面對目前流行的技術不知從何下手,

需要突破技術瓶頸的可以加。

2、在公司待久了,過得很安逸,

但跳槽時面試碰壁。

需要在短時間內進修、跳槽拿高薪的可以加。

3、如果沒有工作經驗,但基礎非常紮實,對java工作機制,

常用設計思想,常用java開發框架掌握熟練的,可以加。

4、覺得自己很牛B,一般需求都能搞定。

但是所學的知識點沒有系統化,很難在技術領域繼續突破的可以加。

5. 群號:高階架構群 Java進階群:180705916.備註好資訊!送架構視訊。


6.阿里Java高階大牛直播講解知識點,分享知識,


多年工作經驗的梳理和總結,帶著大家全面、

科學地建立自己的技術體系和技術認知!