# [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)