點燈坊

失くすものさえない今が強くなるチャンスよ

Promise Chain 之 Multiple Catch

Sam Xiao's Avatar 2021-08-07

雖然實務上 Promise Chain 大都只有一個 catch,但事實上也能同時有多個 catch,可繼續新的 Asynchornous Function,或者將 Error Handling 在不同 catch 分段處理。

Version

ECMAScript 2015

Single Catch

let f = x => Promise.reject(x)

let g = x => Promise.resolve(x)

f (1)
  .then (console.log)
  .then (_ => g (2))
  .then (console.log)
  .catch (console.error)

若 Promise Chain 只有一個 catch,只要其中一個 async function 回傳 Rejected,則後續的 async function 就不會執行,直接執行 catch 部分。

catch000

Multiple Catch

let f = x => Promise.reject(x)

let g = x => Promise.resolve(x)

f (1)
  .then (console.log)
  .catch (console.error)
  .then (_ => g (2))
  .then (console.log)
  .catch (console.error)

若想每個 async function 不互相影響,儘管其中一個 async function 回傳 Rejected,也不會影響之後 async function 執行,可在每個 async function 之後加上 catch

因為 catch 回傳 Resolved,因此 Promise Chain 得以繼續。

catch001

let f = x => Promise.reject(x)

let g = x => Promise.resolve(x)

f (1)
  .then (console.log)
  .catch (console.error)

g (2)
  .then (console.log)
  .catch (console.error)

也可以寫成多個 Promise Chain,則各 async function 亦不會互相影響。

catch002

Rethrow

let f = x => Promise.reject (x)

f (1)
  .then (console.log)
  .catch (console.log)
  .catch (console.error) 

由於 catch 會回傳 Resolved,因此儘管寫了多個 catch,只有第一個 catch 會被執行。

catch004

let f = x => Promise.reject (x)

f (1)
  .then (console.log)
  .catch (e => (console.log (e), Promise.reject (e)))
  .catch (console.error) 

若想讓第二個 catch 也被執行,必須在第一個 catch 內重新回傳 Rejected。

catch003

Conclusion

  • 若要呼叫多個 API,且彼此不互相影響,儘管其中一個 API 失敗,剩下 API 也要繼續執行,則可使用 multiple catch 或者使用 multiple chain 皆可
  • 實務上在處理 API 回傳的 Rejected 時,可將 reset state 寫在第一個 catch 並重新回傳 Rejected,並將處理 status code 寫在第二個 catch