[JavaScript] 2 個簡單方法 讓 Promise 按照順序執行 (mergePromise)

realdennis
4 min readJul 24, 2018

--

我們都知道JavaScript中的異步請求非常繁雜,很多時候我們需要保證一定的執行順序,這時候要怎麼把多個回傳 Promise 的 function(例如 fetch API ,或是自己設計的 return new Promise() )給 merge起來呢?

Photo by Micheile Henderson on Unsplash

此為 ES6 以後的異步處理常碰見的問題。

ES5 以前沒有 Promise 只能 Callback Hell(我們沒有辦法想像那段日子)

解決方法有兩種,分別是用 ES6 與 ES7 的方法。

題目:簡單來說就是多個回傳 Promise 的異步事件的陣列,丟進 mergePromise 函數裡頭,交給你處理。

ajax1/2/3皆使用timeout的函數,而timeout函數則是返回一Promise物件

直接破題 — 先講簡單的方法 :

let solution = quiz => return ES7(quiz);

(誤)

我們可以透過async/await來確保函數執行順序

行1.async函數 行4.確保依序執行完ajax

如果熟悉 ES7 的 async / await 這題當然是直接秒殺,基本上題目若是把異步函數都用 Promise 包過了,在 ES7 的時代跟在寫 C / Python 沒啥差別。

(且連 try catch 也可以寫得簡單明瞭,仿佛在撰寫同步語言。)

經典圖

那讓我們來聊聊當年的人們 (ES6 時代) ,是怎麼解決這個問題吧。

回傳一thenable的Promise,且在此物件中依序更新data陣列。

關於 Promise.resolve 的用法可以參考 MDN ,裡頭提到:

Promise.resolve(value) 方法回傳一個以 value 判定結果的 Promise 物件。若 value 是個 thenable (例如,具有 "then"方法),則回傳的 promise 將依其結果採取其最終狀態;若 value 是 promise,則作為呼叫 Promise.resolve 之結果;其他情形都將回傳以 value 實現的 promise。

首先回到題目:

第一:必須回傳 Promise

我們可以知道其mergePromise函數必須回傳一Promise,可讓呼叫他的主函數透過鏈式調用(then…catch…)來得到結果(res)。

第二:ajax 必須依照順序執行

如果我們不透過 res 去控制,而是直接使用 aj().then,那麼三個ajax會瞬間噴出去,在這個計時器的情況下,不管怎樣都是回傳 2,1,3。

所以精髓來了,因為 res 是一個 thenable 的 promise ,所以 res 每次去等待自己把該 aj 事件完成,並更新data值。

最後:直接告訴你在幹嘛吧?我知道你在查答案 不浪費你時間

這個 function 是這樣的

res =>

(pending…)

欸我在等我自己 => 我自己在等ajax1 => ajax1好了(印一波1) =>更新data

欸我在等我自己 => 我自己在等ajax2 => ajax2好了(印一波2) =>更新data

欸我在等我自己 => 剩下的ajax3完成 => 印一波3 => 更新data

(resolve!)

等完了 那個 call 我的傢伙在打了 .then 後就會得到 res (ajax1/2/3按照次序執行玩且 data 也更新過) ,並將 data 給印出來[1,2,3]。

最後結論:

若題目沒特別要求,應該 ES6 / ES7 都可以用的…吧?

把這個問題都去餵狗 (Google),通常查到到的都是 ES6 的問/答,我猜原因是 ES7 接觸異步事件、事件次序的人,壓根不覺得這是個問題。

沒有 await 解決不了的問題,如果有的話,肯定是你忘記加 async 。

--

--

No responses yet