介紹
JavaScript 的 Promise 可能難以理解。因此,我想記錄一下我對 Promise 的理解方式。
理解 Promise
簡而言之,Promise 是:
“想像你是個孩子。你媽媽承諾下週給你買一個新手機。”
在下周之前,你不知道是否會得到那部手機。你媽媽可能真的會買一部新手機給你,或者她不會。
這就是一個承諾。一個承諾有三種狀態。它們是:
- Pending:你不知道是否會得到那部手機
- Fulfilled:媽媽很高興,她買了一部新手機給你
- Rejected:媽媽不開心,她沒有買手機給你
創建一個 Promise
讓我們將這個轉換成 JavaScript。
這段代碼本身就相當表達清楚。
以下是一般承諾語法的樣子:
使用承諾
現在我們有了承諾,讓我們來使用它:
讓我們運行這個例子並看看結果!
演示:https://jsbin.com/nifocu/1/edit?js,console
串接 Promise
Promise 是可以串接的。
假設你,這個孩子,承諾你的朋友,當你媽媽給你買了一部新手機後,你會展示給他們看。
這是另一個承諾。讓我們寫下來!
備註:我們可以將上述程式碼簡化如下:
讓我們串接這些承諾。你,這個孩子,只能在willIGetNewPhone
承諾完成後,開始showOff
承諾。
這就是如何串接承諾的方式。
承諾是異步的
承諾是異步的。讓我們在調用承諾之前和之後記錄一條消息。
預期的輸出序列是什麼?你可能會預期:
1. before asking Mom
2. Hey friend, I have a new black Samsung phone.
3. after asking mom
然而,實際的輸出序列是:
1. before asking Mom
2. after asking mom
3. Hey friend, I have a new black Samsung phone.
你不會在等待你媽媽的承諾(新手機)時停止玩耍。這就是我們所稱的異步:代碼將在不阻塞或等待結果的情況下運行。任何需要等待承諾才能繼續的代碼都放在.then
中。
以下是完整的 ES5 示例:
ES5, ES6/2015, ES7/Next 中的承諾
ES5 – 大多數瀏覽器
如果包含 Bluebird 承諾庫,演示代碼在 ES5 環境(所有主流瀏覽器 + NodeJs)中是可行的。這是因為 ES5 本身不支持承諾。另一個著名的承諾庫是 Kris Kowal 的 Q。
ES6 / ES2015 – 現代瀏覽器, NodeJs v6
演示代码开箱即用,因为ES6原生支持Promise。此外,借助ES6的功能,我们可以用箭头函数进一步简化代码,并使用const
和let
。
以下是完整的ES6代码示例:
请注意,所有的var
都替换为了const
。所有的function(resolve, reject)
都简化为(resolve, reject) =>
。这些改动带来了一些好处。
ES7 – Async/Await
ES7引入了async
和await
语法。它使得异步语法更易于理解,无需使用.then
和.catch
。
用ES7语法重写我们的示例:
承諾及其使用時機
為何我們需要承諾?在承諾出現之前,世界是怎樣的?在回答這些問題之前,讓我們回歸基礎。
普通函數與非同步函數
讓我們看看這兩個例子。兩個例子都執行了兩個數字的加法:一個使用普通函數進行加法,另一個則是遠程加法。
普通函數進行兩數相加
非同步函數進行兩數相加
如果你使用普通函數進行數字相加,你會立即得到結果。然而,當你發出遠程調用以獲取結果時,你需要等待,無法立即得到結果。
您無法確定是否會得到結果,因為伺服器可能會宕機、回應緩慢等。您不希望整個流程在等待結果時被阻塞。
調用API、下載文件和讀取文件是您將執行的一些常見的異步操作。
您不需要為異步呼叫使用Promise。在Promise之前,我們使用回調函數。回調函數是您在獲得返回結果時調用的函數。讓我們修改前面的例子以接受一個回調函數。
後續的異步操作
我們希望將數字加三次,而不是一次加一個。在普通函數中,我們會這樣做:-
這是使用回調函數的外觀:
示例:https://jsbin.com/barimo/edit?html,js,console
這種語法由於深度嵌套的回調函數而較不友好。
避免深度嵌套的回調函數
Promise 可以幫助你避免深度嵌套的回調函數。讓我們看看同一示例的 Promise 版本:
使用 Promise,我們通過 .then
展平回調。在某種程度上,它看起來更乾淨,因為沒有回調嵌套。使用 ES7 的 async
語法,你可以進一步增強這個示例。
可觀察對象
在你決定使用 Promise 之前,有一種新興的技術可以幫助你處理異步數據,稱為 可觀察對象
。
讓我們看看用可觀察對象編寫的相同示例。在這個示例中,我們將使用 RxJS 來處理可觀察對象。
可觀察對象可以做更多有趣的事情。例如,只需一行代碼就可以使用 delay
函數延遲 3 秒
,或者重試,以便你可以重試某個調用一定的次數。
您可以閱讀我的一篇關於RxJs的文章這裡。
結論
熟悉回調和承諾是非常重要的。理解它們並加以應用。暫且不必擔心可觀察對象。根據具體情況,這三者都可能成為您開發中的要素。
Source:
https://www.digitalocean.com/community/tutorials/understanding-javascript-promises