JavaScript: Promises 介紹及爲何 Async

異步函數在JavaScript中有好有壞。好的一面是異步函數是非阻塞的,因此很快 - 特別是在Node.js上下文中。缺點是處理異步函數可能很麻煩,因為有時必須等待一個函數完成才能在進行下一次執行之前獲得“回調”。

有一些方法可以發揮異步函數調用的優勢並正確處理它們的執行,但其中一種方法遠遠優於其他方法(Spoiler:它是Async / Await)。在本文中,您將瞭解使用Promises和Async/Await的來龍去脈,以及我們對兩者之間如何比較的看法。

Promises vs. Callbacks

作為JavaScript或Node.js開發人員,正確理解Promises和Callbacks之間的區別以及它們如何協同工作至關重要。

兩者之間存在微小但重要的差異。在每個Promise的核心,都有一個Callback解決某些數據(或錯誤),這些數據會被調用到Promise。

回調處理程序:

JavaScript: Promises 介紹及為何 Async/Await 最終取得勝利

調用validatePassword()功能:

JavaScript: Promises 介紹及為何 Async/Await 最終取得勝利

下面的代碼片段顯示了驗證密碼的完整端到端檢查(它是靜態的,必須匹配“bambi”):

JavaScript: Promises 介紹及為何 Async/Await 最終取得勝利

代碼註釋得非常好,但是,如果您感到困惑,catch只會在reject()從promise調用時執行。由於密碼不匹配,我們調用reject(),因此“catch”錯誤並將其發送到done()函數。Promises

與傳統的基於回調的方法相比,Promise為執行、組合和管理異步操作提供了更簡單的替代方案。它們還允許你使用類似同步try / catch的方法處理異步錯誤。

Promise還提供三種唯一的狀態

  1. Pending- promise的結果尚未確定,因為將產生其結果的異步操作尚未完成。
  2. Fulfilled - 異步操作已完成,並且promise有值。
  3. Rejected - 異步操作失敗,promise永遠不會實現。在被拒絕狀態下,promise有一個reason可以指示操作失敗的原因。

當promise在pending狀態時,它可以轉換為fulfilled或rejected的狀態。然而,一旦promise得到fulfilled或rejected,它將永遠不會過渡到任何其他狀態,其value或失敗原因不會改變。

缺點

Promise並沒有去解決所謂的“回調地獄”,“回調地獄”實際上只是一系列嵌套函數調用。當然,對於一個調用沒關係。但是對於多個調用,您的代碼將會難以閱讀和維護。

在Promises中循環

為了避免使用JavaScript進行深度嵌套回調,假設可以簡單地遍歷Promises,將結果返回給對象或數組,並在完成後停止。不幸的是,這並不容易; 由於JavaScript的異步特性,如果循環遍歷每個Promise,在代碼完成時不會調用“done”事件。

處理這種情況的正確方法是使用Promise.all()。這個函數在它被標記為已完成之前等待所有的Fulfillments(或第一次rejection)。

錯誤處理

使用多個嵌套的Promise調用進行錯誤處理就像蒙著眼睛的駕駛汽車一樣。祝你好運找出哪個Promise犯了錯誤。你最好的選擇是完全刪除catch()方法並選擇加入全局錯誤處理程序,如下所示:

瀏覽器

JavaScript: Promises 介紹及為何 Async/Await 最終取得勝利

Node.js

JavaScript: Promises 介紹及為何 Async/Await 最終取得勝利

注意:以上兩個選項是確保捕獲錯誤的兩種方法。如果錯過了添加catch()方法,它將被代碼吞噬。Async/Await?

Async/Await允許我們編寫看起來是同步的異步JavaScript。在本文的前幾部分中,您瞭解了Promises - 它應該簡化異步流並避免回調地獄但它沒有。

回調地獄?

Callback-hell是一個用於描述以下場景的術語:

注意:舉個例子,這是一個API調用,可以從一個數組中獲得4個特定用戶。

JavaScript: Promises 介紹及為何 Async/Await 最終取得勝利

這樣的代碼這很難看,也佔用了大量的空間。Async/Await是JavaScript的最新和最好的東西,它允許我們不僅避免回調地獄,而且確保我們的代碼乾淨並且錯誤被正確捕獲。我發現Async/Await最令人著迷的是它構建在Promises之上(非阻塞等),並且允許代碼可讀並且就像讀取它是同步的一樣。這就是關鍵所在。

注意:以下是一組API調用的示例,用於從一個數組中檢索4個用戶,超過一半的代碼行:

JavaScript: Promises 介紹及為何 Async/Await 最終取得勝利

代碼這樣寫比較優雅,對嗎?因為Async/Await是建立在Promises之上的,所以你甚至可以在關鍵字await使用Promise.all():

JavaScript: Promises 介紹及為何 Async/Await 最終取得勝利

注意:由於同步特性,Async/await稍微慢一些。連續多次使用它時應該小心,因為await關鍵字會停止執行後面的所有代碼 - 就像在同步代碼中一樣。如何開始使用Async/Await?

使用Async/Await非常容易理解和使用。實際上,它可以在最新版本的Node.js中本地使用,並且正在迅速融入瀏覽器。現在,如果你想在客戶端使用它,你需要使用Babel。

異步Async

讓我們從async關鍵字開始。它可以放在function之前,如下所示:

JavaScript: Promises 介紹及為何 Async/Await 最終取得勝利

等待Await

關鍵字await使JavaScript等待promise繼續並返回其結果。如下所示:

JavaScript: Promises 介紹及為何 Async/Await 最終取得勝利

完整的例子

JavaScript: Promises 介紹及為何 Async/Await 最終取得勝利

為什麼Async/Await更好?

現在我們已經瞭解了Promises和Async/Await所提供的很多內容,讓我們回顧一下為什麼Stream認為Async/Await是代碼庫的最佳選擇。

  1. Async/Await允許使用更少的代碼行,更少的輸入和更少的錯誤,提供簡潔明瞭的代碼庫。最終,它使複雜的嵌套代碼再次可讀。
  2. 使用try/catch處理錯誤(在一處,而不是在每個調用中)
  3. 錯誤堆棧是有意義的,而不是從Promises收到的模糊錯誤,它們很大並且很難找到錯誤發生的位置。最重要的是,錯誤指向錯誤發生的函數。

最後的想法

可以說Async/Await是過去幾年中添加到JavaScript中的最強大的功能之一。

花了不到一天的時間來理解語法,看看我們的代碼庫在這方面是多麼糟糕。將我們所有基於Promise的代碼轉換為Async/Await總共花費了大約兩天時間,這實際上是一個完全重寫 - 這只是為了說明使用Async/Await時需要更少的代碼。

鏈接:https://juejin.im/post/5bac3e0b6fb9a05d1e0e6167


分享到:


相關文章: