# [JavaScritp] 好的 `async/await` 處理錯誤及執行流程
###### tags: `前端筆記` `非同步處理`
一般情況中在 `async function` 內都會以 `try...catch` 捕捉錯誤。
假設目前有的流程是:
1. 以 userID 確認該 user 是否存在(是:回傳 userData,否:error)
2. 以 userData 取得 user 的貼文(是:回傳 userPosts,否:error)
3. 最後再把得到的資料渲染到頁面上
```javascript=
const processUserDataRequest = async(userID) => {
try {
const userData = await getUserData(userID);
const userPosts = await getUserPosts(userData);
showUserInfoPage(userData, userPosts);
} catch(error) {
errorHandler(error);
}
};
processUserDataRequest(13);
```
## 如果想要知道是哪個 `Promise` 出狀況的話呢?
上面的例子雖然可以捕捉錯誤,但是如果想知道是哪個 `Promise` 出了問題勢必得要多寫幾個 `try...catch`:
```javascript=
const processUserDataRequest = async(userID) => {
let userData;
let userPosts;
try {
userData = await getUserData(userID);
} catch(error) {
console.log(`Error: ${error}`)
}
try {
userPosts = await getUserPosts(userData)
} catch(error) {
console.log(`Error: ${error}`);
}
showUserInfoPage(userData, userPosts);
};
processUserDataRequest(13);
```
這樣子看起來如果有多個請求的話就得要寫相同數量的 `try...catch`,而且因為 Block scope 的緣故,必須要放一個變數在 Block 外,讓不同 `try...catch` 的區塊內都可以拿到變數的存取權。
## 新增一個 helper function 先處理 `Promise` 的狀態
以這篇文章 [Better error handling with async/await](https://dev.to/sobiodarlington/better-error-handling-with-async-await-2e5m) 作者分享可以把判斷 `Promise` 的狀態分成一個獨立的 function。該 function 會依照 `Promise` 實際的狀態回傳陣列,我們只要判斷陣列的值就可以知道請求的成功與否,也可以對個別錯誤客製化處理。
```javascript=
const promiseHandler = (promise) => {
return promise
.then((data) => [null, data])
// 確保回來的是 Promise
.catch((error) => Promise.resolve[error, null]);
};
const processUserDataRequest = async(userID) => {
const [userDataError, userData] = promiseHandler(getUserData(userID));
if (userDataError) {
errorHandler(userDataError);
throw new Error(...);
}
const [postsError, posts] = promiseHandler(getUserPosts(userData));
if (postsError) {
errorHandler(userDataError);
throw new Error(...);
}
showUserInfoPage(userData, userPosts);
}
```
## 建立 procedural(程序)function 將小塊的 `async function` 統整為一個連續的動作
`procedural function` 以 process 開頭命名,語譯化 => 步驟。
並把數個小動作放進去,保持可以單獨叫用一個步驟,或者是一次整個步驟的靈活性。
```javascript=
// 組合網址
const buildURL = (baseUrl, query) => {
return `${baseUrl}?type=${query}`;
};
// 打資料
const requestData = async(apiURL) => {
const respose = await fetch(apiURL);
const data = await response.json();
return data;
};
// 渲染 DOM
const render = (ele, data) => {
const element = document.querySelector(ele);
element.innerHTML = data;
}
// procedural function 將每一步驟變成一個連續動作
const processData = async({ baseUrl, query }) => {
const url = bhildURL(baseUrl, query);
const data = await requestData(url);
render('body', data);
};
```
## 參考資料
1. [Better error handling with async/await](https://dev.to/sobiodarlington/better-error-handling-with-async-await-2e5m)
2. [Callbacks, Promises, Async Await | JavaScript Fetch API Explained](https://www.youtube.com/watch?v=VmQ6dHvnKIM)(約 1 小時的左右有介紹 procedural flow)