JavaScript 如何讓多個 async/await 函式同時執行 ── 從實際案例了解 Promise.all 和 Promise.allSettled 的區別

林鼎淵
Dean Lin
Published in
Sep 19, 2022

--

大家可以在瀏覽器按下「F12」,於 Console 的分頁貼上文中的程式碼來驗證喔!

撰寫前端時,一個頁面往往需要 call 多支 API 才能完成渲染。

為了等資料回傳,我們通常都會搭配 await,但有時 API 之間並沒有要求執行的順序(下一隻 API 並不需要使用上一隻 API 回傳的結果作為參數)。

在這樣的情境下,如果還是採取順序執行的方案,當需要 call 多支 API 時就會浪費使用者許多時間。下面筆者就先舉一個直觀的範例:

請把 api1()、api2()、api3() 想像成 call API 的函式。
在瀏覽器 Console 分頁的執行結果

在上圖中,我們可以看到總執行時長為 1512 ms,有許多時間被浪費在等待上一支 API 執行完畢。

▋採用 Promise.all 來解決問題

既然 API 之間沒有要求執行的順序,我們就可以將其改寫為 Promise.all,讓函式同時執行來提升效率:

請把 api1()、api2()、api3() 想像成 call API 的函式。
在瀏覽器 Console 分頁的執行結果

經過改寫,我們可以從輸出的結果中看到,總執行時長從 1512 ms 下降到 502 ms,這對使用者來說是非常有感的提升。

▋Promise.all 會碰到什麼問題?

儘管透過 Promise.all 已經提升了不少效率,但這個方案在其中一支 API 吐 error 時,情況就會變得很麻煩。

請把 api1()、api2()、api3() 想像成 call API 的函式。

如果執行上面的程式,你會發現透過 catch 我們成功抓到 “error” 的錯誤訊息,但其他執行成功的訊息全部都消失了(Promise.all的失敗優先原則)

有時這種「只有成功 or 失敗」的結果的確是我們要的,但在實務上,我們未必需要所有 API 都執行成功,面對錯誤我們可以設計另一套處理方案。

▋導入 Promise.allSettled 解決問題

為了取得所有回傳結果,我們可以改為使用 Promise.allSettled,在輸出的時候,它會多出一個 status 的參數,用來說明執行結果的成功 or 失敗。

請把 api1()、api2()、api3() 想像成 call API 的函式。
在瀏覽器 Console 分頁的執行結果

從上圖我們可以看到,無論執行的結果是成功或失敗,我們都能取得那些執行成功後的訊息。

備註: Node.js 從 v12.9.0 開始支援 Promise.allSettled 的語法,大多數的瀏覽器也在 2019 年後支援;針對少數不支援的環境,你可以透過 npm 套件自行擴充,如:promise.allsettled

▋總結

  1. 如果 API 沒有要求執行的順序,但需要等每個 API 都執行完畢後才能進入下一步,那 Promise.all 同時執行的機制可以有效縮短執行時間。
  2. 為了解決 Promise.all 失敗後,成功訊息一併消失的問題,可以改用 Promise.allSettled 來取得所有回傳結果。
▶︎ 如果這篇文章有幫助到你1. 可以點擊下方「Follow」來追蹤我~
2. 可以對文章拍手讓我知道 👏🏻
你們的追蹤與鼓勵是我繼續寫作的動力 🙏🏼▶︎ 如果你對工程師的職涯感到迷茫1. 也許我在iT邦幫忙發表的系列文可以給你不一樣的觀點 💡
2. 也歡迎您到書局選購支持,透過豐富的案例來重新檢視自己的職涯

--

--

林鼎淵
Dean Lin

職涯中培育過多名工程師,🧰 目前在外商公司擔任 Software Specialist |✍️ 我專注寫 (1)最新技術 (2)團隊合作 (3)工程師職涯的文章,出版過 5 本專業書籍|👏🏻 如果對這些主題感興趣,歡迎點擊「Follow」來關注我~