JavaScript 核心觀念(82) - ES6 章節:Async/Await - 撰寫高可用性高的錯誤捕捉

前言

接下來聊一下該如何撰寫可用性高的錯誤捕抓。

撰寫高可用性高的錯誤捕捉

開始之前先來看一下範例程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function promiseFn (boolean) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if(boolean) {
resolve('resolve');
} else {
reject('reject')
}
}, 1000)
})
}

const asyncFn = async () => {
try {
const res = await promiseFn(true);
console.log(res);
} catch(error) {
console.log('error', error);
}
}

其實我們可以看到上面程式碼中如果我們要使用 asyncawait 時都會建議使用 try...catch... 來包覆,否則無法正確捕捉到錯誤。

但這個寫法狀況下並不是那麼漂亮,因為變成每一次使用 asyncawait 時都必須寫很多 try...catch...,因此 try...catch... 結構是可以省略的,但這邊要注意 catch 的部分,因為我們會使用 try...catch... 的主要原因在於捕捉錯誤並提示出來,因此 catch 的部分必須是具有一制性的(意指統一行為,如 window.alert(error); 等)。

那麼首先這邊我們接下來看一下該如何改寫,首先先宣告一個 catchError 函式,並且將會傳入一個 async function,一率就會從這邊統一處理 catch

1
2
3
4
5
const catchError = (asFn) => {
return asFn.catch((error) => {
console.log('error', error);
})
}

因此我們就可以這樣子呼叫使用

1
catchError(asyncFn(1));

catchError

但這個寫法並不是那麼好,因為假設今天如果要傳入參數的話,然後剛好又是一個迴圈是要戳 API 的

1
2
3
[1, 2].forEach(catchError(async (n) => {
await axios.get(`https://jsonplaceholder.typicode.com/todos/${n}`)
}))

你會發現根本沒有辦法傳入迴圈的值,因此上面是第一種常見寫法,如果要解決這種狀況的話,就要改一下 catchError,我們必須在外層再包一個函示

1
2
3
4
5
6
7
const catchError = (asFn) => {
return (n) => {
return asFn(n).catch((error) => {
console.log('error', error);
})
}
}

看到這邊你應該會發現這個概念就是一個閉包概念,因此這樣子你再跑迴圈時,才能夠正確的將值往裡面傳遞。

而這個其實是一種設計模式,稱之為 Functional programming 的部分,利用的就是一級函式概念來實作,我早期也有寫過相關的文章,所以也提供參考

簡單趣談 Functional Programming in JavaScript

參考文獻