---
# System prepended metadata

title: （穎旻試教版本）第三堂 - axios 搭配 Async/Await 再進化
tags: ["前端家教師資培訓班\_- 2024"]

---

# （穎旻試教版本）第三堂 - axios 搭配 Async/Await 再進化

# 課程大綱

1. Promise 與 Async/Await 比較
    - 1 個觀念 - 20min
2. 錯誤與例外處理
    - 1 個觀念 - 20min
3. axios 搭配 Async/Await 與錯誤管理整合
    - 1 個觀念 - 20min
# 1. Promise 與 Async/Await 比較
Promise：
```jsx
function fetchData() {
    return new Promise(function(resolve) {
        setTimeout(() => {
            resolve("資料已經獲取");
        }, 2000);
    });
}

function getDataWithThen() {
    console.log("開始獲取資料...");
    fetchData().then(function (data) {
        console.log(data);
    });
}

getDataWithThen();
```
Async/Await：
```jsx
function fetchData() {
    return new Promise(function(resolve) {
        setTimeout(() => {
            resolve("資料已經獲取");
        }, 2000);
    });
}

// 使用 Async/Await 的作法
async function getData() {
    console.log("開始獲取資料...");
    const data = await fetchData();
    console.log(data);
}

getData();
```

**使用 async await：提升可讀性、減少複雜性**

async/await 是 JavaScript 中用於處理非同步的一種語法糖，讓程式碼更好理解

- **`async`** 關鍵字用於定義一非同步函式，這個函式將回傳一個 Promise
- 在 **`async`** 函式內部，可以使用 **`await`** 關鍵字來等待一個 Promise 被解析（resolved）。
- async 函式內部可以使用 [`await`](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Operators/await) ，他可以讓程式碼看起來像同步的，它會暫停此 async 函式的執行，並且等待解析，解析完之後會回傳解析值，並繼續此 async 函式的執行。

## axios 寫法如下
> [請先申請 api 再練習以下程式碼](https://livejs-api.hexschool.io/) 

使用 axios 套件處理非同步操作 - GET：

```jsx
const api_path = "自訂路徑";

// Promise 結構的寫法
const getProductList = () => {
  axios.get(`https://livejs-api.hexschool.io/api/livejs/v1/customer/${api_path}/products`)
    .then(response => {
	    console.log(response.data.products);
    })
};
getProductList();

// async / await 寫法
const getProductList = async () => {
    const response = await axios.get(`https://livejs-api.hexschool.io/api/livejs/v1/customer/${api_path}/products`);
    console.log(response.data.products);
};
getProductList();
```
使用 axios 套件處理非同步操作 - POST：
```jsx
const api_path = "自訂路徑";

// Promise 結構的寫法
function addCartItem(id){
  axios.post(`https://livejs-api.hexschool.io/api/livejs/v1/customer/${api_path}/carts`,{
    data: {
      productId: id,
      quantity: 1
    }
  }).
    then(function (response) {
      alert("加入購物車成功");

    })
}
addCartItem('YO5KnEkeFBIEVrGDA0Id')

// async / await 寫法
const addCartItem = async (id) => {
    const response = await axios.post(`https://livejs-api.hexschool.io/api/livejs/v1/customer/${api_path}/carts`, {
        data: {
            productId: id,
            quantity: 1
        }
    });

    alert("加入購物車成功");
};
addCartItem('hLk58hbZpjMMZdEPbce0')
```

# 2. 錯誤與例外處理
錯誤與[常見錯誤種類](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#error_types)

```jsx
console.log(a);  // ReferenceError: a is not defined
```
自訂錯誤：[JS error 介紹](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/Error)
```jsx
const a = new Error("姓名欄位沒有填寫") // 建立一個 Error 物件，並指定 message
a.name = "驗證失敗"; // 自訂錯誤類型的名稱

console.log(a); // 驗證失敗: 姓名欄位沒有填寫
console.log(a.name); // '驗證失敗'
console.log(a.message); // '姓名欄位沒有填寫'
```


**為什麼需要學例外處理呢？**
為了在這些錯誤情況發生時，能夠加以控制或管理，稱之為例外處理，這邊我們要來介紹到 
1. try...catch 語法與範例
    ```jsx
    try {
        ...
    } catch (error) {
        ...
    }
    ```
    ```jsx
    try {
        console.log(a); // 這邊出錯，但不會導致網頁死掉
    } catch (error) { // catch 將錯誤捕捉起來，並產生一個包含詳細錯誤資訊的物件，將物件作為參數 error 使用
        console.log(error) 
    }
    console.log('錯誤') // 這行會被執行！
    ```
    ```jsx
    // 自訂錯誤也可以用 try catch 捕捉

    const a = new Error("姓名欄位沒有填寫")
    a.name = "驗證失敗"

    try{
        throw a;
    } catch(error){
        console.log(error)
    }
    ```

2. Promise 的 catch() 語法與範例

    ```jsx
    axios.then(function() {
        ...
    }).catch(function(error) {
        console.log(error)
    })
    ```
    
    ```jsx
    const getProductList = () => {
      axios.get(`https://livejs-api.hexschool.io/api/livejs/v1/customer/${api_path}/products`)
        .then(function(response) {
            console.log(response.data.products);
        })
        .catch(function(error) {
            console.log(error)
        })
    };
    ```

    ```jsx
    // promise 自訂錯誤使用 catch 捕捉

    function customPromise() {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          const randomNumber = Math.floor(Math.random() * 100) + 1;
          if (randomNumber % 2 === 0) {
            resolve(randomNumber);
          } else {
            reject(new Error(`奇數: ${randomNumber}`));
          }
        }, 1000);
      });
    }

    // 使用範例

    function count(){
      customPromise()
      .then(result => console.log(`成功: ${result}`))
      .catch(error => console.error(`失敗: ${error.message}`));
    }

    count();
    ```
    
   
    - [axios 自訂錯誤物件](https://github.com/axios/axios/blob/main/lib/core/AxiosError.js)


# 3. axios 搭配  Async/Await 與錯誤管理整合

```jsx

// GET
const api_path = "自訂路徑";
const getProductList = async () => {
    try {
        const response = await axios.get(`https://livejs-api.hexschool.io/api/livejs/v1/customer/${api_path}/products`);
        console.log(response)
    } catch (error) {
        console.error("取得產品列表失敗", error.response.data);
        alert("取得產品列表時發生錯誤，請稍後再試。");
    }
};

// POST
const addCartItem = async (id) => {
    try {
        const response = await axios.post(`https://livejs-api.hexschool.io/api/livejs/v1/customer/${api_path}/carts`, {
            data: {
                productId: id,
                quantity: 1
            }
        });

        console.log(response)
        alert("加入購物車成功");
    } catch (error) {
        console.error("加入購物車失敗", error.response.data);
        alert("加入購物車時發生錯誤，請稍後再試。");
    }
};
```