[譯]JavaScript: Promises 介紹及為何 Async/Await 最終取得勝利
原文地址: ofollow,noindex">JavaScript: Promises and Why Async/Await Wins the Battle
非同步函式在JavaScript中有好有壞。好的一面是非同步函式是非阻塞的,因此很快 - 特別是在Node.js上下文中。缺點是處理非同步函式可能很麻煩,因為有時必須等待一個函式完成才能在進行下一次執行之前獲得“回撥”。
有一些方法可以發揮非同步函式呼叫的優勢並正確處理它們的執行,但其中一種方法遠遠優於其他方法(Spoiler:它是Async / Await)。在本文中,您將瞭解使用Promises和Async/Await的來龍去脈,以及我們對兩者之間如何比較的看法。
Promises vs. Callbacks
作為JavaScript或Node.js開發人員,正確理解 Promises
和 Callbacks
之間的區別以及它們如何協同工作至關重要。
兩者之間存在微小但重要的差異。在每個 Promise
的核心,都有一個 Callback
解決某些資料(或錯誤),這些資料會被呼叫到 Promise
。
回撥處理程式:

呼叫validatePassword()功能:

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

catch
只會在
reject()
從
promise
呼叫時執行。由於密碼不匹配,我們呼叫
reject()
,因此
“catch”
錯誤並將其傳送到
done()
函式。
Promises
與傳統的基於回撥的方法相比, Promise
為執行、組合和管理非同步操作提供了更簡單的替代方案。它們還允許你使用類似同步 try / catch
的方法處理非同步錯誤。
Promise還提供三種唯一的狀態:
-
Pending
-promise
的結果尚未確定,因為將產生其結果的非同步操作尚未完成。 -
Fulfilled
- 非同步操作已完成,並且promise
有值。 -
Rejected
- 非同步操作失敗,promise
永遠不會實現。在被拒絕狀態下,promise
有一個reason
可以指示操作失敗的原因。
當 promise
在 pending
狀態時,它可以轉換為 fulfilled
或 rejected
的狀態。然而,一旦 promise
得到 fulfilled
或 rejected
,它將永遠不會過渡到任何其他狀態,其 value
或失敗原因不會改變。
缺點:-1:
Promise
並沒有去解決所謂的“回撥地獄”,“回撥地獄”實際上只是一系列巢狀函式呼叫。當然,對於一個呼叫沒關係。但是對於多個呼叫,您的程式碼將會難以閱讀和維護。
在Promises中迴圈:ferris_wheel:
為了避免使用JavaScript進行深度巢狀回撥,假設可以簡單地遍歷 Promises
,將結果返回給物件或陣列,並在完成後停止。不幸的是,這並不容易; 由於JavaScript的非同步特性,如果迴圈遍歷每個 Promise
,在程式碼完成時不會呼叫 “done”
事件。
處理這種情況的正確方法是使用 Promise.all()
。這個函式在它被標記為已完成之前等待所有的 Fulfillments
(或第一次 rejection
)。
錯誤處理:bomb:
使用多個巢狀的 Promise
呼叫進行錯誤處理就像蒙著眼睛的駕駛汽車一樣。祝你好運找出哪個 Promise
犯了錯誤。你最好的選擇是完全刪除 catch()
方法並選擇加入全域性錯誤處理程式,如下所示:
瀏覽器:

:

catch()
方法,它將被程式碼吞噬。
Async/Await?
Async/Await
允許我們編寫看起來是同步的非同步JavaScript。在本文的前幾部分中,您瞭解了 Promises
- 它應該簡化非同步流並避免回撥地獄但它沒有。
回撥地獄?:fire:
Callback-hell
是一個用於描述以下場景的術語:
注意:舉個例子,這是一個API呼叫,可以從一個數組中獲得4個特定使用者。

這樣的程式碼這很難看,也佔用了大量的空間。 Async/Await
是JavaScript的最新和最好的東西,它允許我們不僅避免回撥地獄,而且確保我們的程式碼乾淨並且錯誤被正確捕獲。我發現 Async/Await
最令人著迷的是它構建在 Promises
之上(非阻塞等),並且允許程式碼可讀並且就像讀取它是同步的一樣。這就是關鍵所在。
注意:以下是一組API呼叫的示例,用於從一個數組中檢索4個使用者,超過一半的程式碼行:

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

Async/await
稍微慢一些。連續多次使用它時應該小心,因為
await
關鍵字會停止執行後面的所有程式碼 - 就像在同步程式碼中一樣。
如何開始使用Async/Await?:computer:
使用 Async/Await
非常容易理解和使用。實際上,它可以在最新版本的Node.js中本地使用,並且正在迅速融入瀏覽器。現在,如果你想在客戶端使用它,你需要使用Babel。
非同步Async
讓我們從 async
關鍵字開始。它可以放在 function
之前,如下所示:

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

完整的例子

為什麼Async/Await更好?:grin:
現在我們已經瞭解了 Promises
和 Async/Await
所提供的很多內容,讓我們回顧一下為什麼Stream認為 Async/Await
是程式碼庫的最佳選擇。
Async/Await try/catch Promises
最後的想法:page_with_curl:
可以說 Async/Await
是過去幾年中新增到JavaScript中的最強大的功能之一。
花了不到一天的時間來理解語法,看看我們的程式碼庫在這方面是多麼糟糕。將我們所有基於 Promise
的程式碼轉換為 Async/Await
總共花費了大約兩天時間,這實際上是一個完全重寫 - 這只是為了說明使用Async/Await時需要更少的程式碼。