---
# System prepended metadata

title: 第二堂：非同步與 This
tags: [' 六角學院', 2022 Vue 作品實戰班]

---

---
title: 第二堂：非同步與 This
tags: 2022 Vue 作品實戰班, 六角學院
date: 20220114
image:
---

# 第二堂：非同步與 This
## 課前閒聊
### 作品
#### 素材選擇（注意授權）
* [六角作品牆](https://https://works.hexschool.io/#/)
* [unsplash](https://unsplash.com/)
#### 主題&課程API說明
* 本周開始想主題，有方向後查找[unsplash](https://unsplash.com/)，登入[unsplash](https://unsplash.com/)網站後可分將圖片分類
* 同一作者的作品風格較接近
* 電商網站產品圖至少20+，一個產品可能會有多張圖片
* 課程提供API能被突破限制(ex:node.js轉接，類似多加欄位，並無儲存資料)
* 課程API為NoSQL，除必要欄位外，其餘可客製化
#### 常見主題
* 咖啡、旅遊、服飾、餐飲
#### 特殊主題（可挑戰，但請注意素材來源授權）
* 音樂、求職網、遊戲、電影

## Axios / 非同步 與 API 說明


### 同步
特性 1：依序執行
特性 2：一個完成，才執行下一個，所以當某一行程式碼噴錯，後方程式碼就完全不能動了


### 非同步
特性：一次可以做很多事情


### ex1 同步語言
JS 是同步語言。
```javascript=
    let data = '';
    function updateData() {
      data = '小明';
    }
    updateData()
    console.log(data); // 結果為？
```
![](https://i.imgur.com/DYHyuHc.png)

- A:小明
- 先執行13行
在14行宣告函式(還沒執行)
在17行呼叫函式並行它，進入執行堆疊，進入執行堆疊後，把 "小明" 附在 data 上面
在18行看到的 data 是 "小明"
- 同步語言特點:中間有出錯，後面就不會動
- **Javascript 是同步語言**

### ex2 立即函式
```javascript=
    let data = '';
    (function() {
      data = '小明';
    })();
    console.log(data);
```
- 立即函式:立即函式會即刻被執行
- A:小明，ex2 本質上跟 ex1 的函式一樣

### ex3 setTimeout()
```javascript=
    let data = '';
    setTimeout(() => {
      data = '小明';
    }, 10);
    console.log(data);
```
<!-- - setTimeout 延遲了10秒 -->
- A:""，空字串
- setTimeout()為非同步事件，屬於callback function
- 同步語言會依序執行，非同步事件無法依序執行，當非同步事件執行時，會先放在事件佇列(Event Queue中)，等一般程式碼執行結束後，最後才執行

同步語言下的非同步事件與事件佇列:
![](https://i.imgur.com/MaSXnzL.png)
<!-- - setTimeout 會被移到事件佇列，最後才執行 -->

### ex4
```javascript=
    let data = '';
    setTimeout(() => {
      data = '小明';
    }, 0);
    console.log(data);
```
- A:""，空字串
- setTimeout()放在事件佇列(Event Queue中)時，與設定秒數無關，仍然會最後才被執行

### Promise
#### 巢狀 callback hell(波動拳)
![](https://i.imgur.com/w7hwCkU.png)
- 在以前做非同步事件或call api，會用巢狀式 callback function 結構，一直往裡面加 callback function
- Promise 結構，解決巢狀結構不好閱讀的問題

#### 先瞭解如何呼叫 Promise
```javascript=
    const promiseSetTimeout = (status) => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          if (status) {
            resolve('promiseSetTimeout 成功')
          } else {
            reject('promiseSetTimeout 失敗')
          }
        }, 10);
      })
    }
```
![](https://i.imgur.com/1OcJQEJ.png)

<!-- - new Promise
- 第1個參數回傳成功的結果
- 第2個參數回傳失敗的結果 -->
- Promise結構:
定義 promiseSetTimeout ，並return 回傳 new Promise的方法。
new Promise的方法中，成功回傳resolve的結果，失敗回傳reject的結果，**resolve、 reject ，同時只會得到一個結果**
- Promise，通常用於接外部非同步資料
- 每次使用Promise時，都要加上.then、.catch，確保接收到成功或失敗資訊
- [JavaScript Promise 全介紹](https://wcc723.github.io/development/2020/02/16/all-new-promise/)


#### 成功案例，用1表示true
- 只要看到函式庫是 Promise Base 開發，都可以這樣接
ex:課程使用axios
本處省略.catch
``` javascript
promiseSetTimeout(1)
    .then(function(res){
        console.log(res);
    })
```
#### 失敗，用0表示false
- 本處省略.then
``` javascript
promiseSetTimeout(0)
    .catch(function(err){
        console.log(err);
    })
```
#### 正常案例.then、.catch
``` javascript
promiseSetTimeout(0)
    .then(function(res){
        console.log(res);
    })
    .catch(function(err){
        console.log(err);
    })
```
#### 依序鏈結(多個promise串接)
- 多個promise串接時，每組.then會與.catch互相對應，第一個.then會對應第一個.catch，以此類推
因.then與.catch，同時只會得到一個結果，如果回傳為.catch，則對應的.then會被**跳過**
- 原生Web API語法fetch，也會利用.then跳至下一段
``` javascript
promiseSetTimeout(0)
    .then(function(res){
        console.log(res);
        return promiseSetTimeout(1)
    })
    .then(function(res){
        console.log(res);
        return promiseSetTimeout(1)
    })
    .catch(function(err){
        console.log(err);
    })
    .catch(function(err){
        console.log(err);
    })
```
## AXIOS
> 是一種promise-based
> promise是JS語法，axios基於promise而開發的套件
* [randomuser](https://randomuser.me/)
* [codpen練習](https://codepen.io/ldddl/pen/ExwrBJb)

### AXIOS 鏈接
``` javascript
console.clear();
axios.get('https://randomuser.me/api/')
 .then((res) => {
  // console.log(res);
  const { seed } = res.data.info; // 解構
  console.log(seed);
  return axios.get(`https://randomuser.me/api/?seed=${seed}`)
})
.then((res) => {
  console.log(res);
  })
```
### AXIOS 示範錯誤連接
#### console.dir
> 無法在一般 console.log 查伺服器回傳的物件格式時，可用 console.dir
> console.dir 會讓從 server 回傳的錯誤訊息變成可以展開的物件
``` javascript
console.clear();
axios.get('https://randomuser.me/api/')
 .then((res) => {
  // console.log(res);
  const { seed } = res.data.info; // 解構
  console.log(seed);
  return axios.get(`https://randomuser.me/api/?seed=${seed}`)
})
.then((res) => {
  console.log(res);
  })
```
## 課程API
[課程API](https://hexschool.github.io/vue3-courses-swaggerDoc/)
### 一般用戶(前台)、管理者(後台)
![管理者](https://i.imgur.com/Btb4JXp.png)
* 管理者(後台)API:網址中，有admin

![一般用戶](https://i.imgur.com/ZhAnj2B.png)
* 一般用戶(前台)API:網址中，無admin
### API單、複數
![課程API](https://i.imgur.com/QzMakqP.png)
* 加s表示複數 → (orders)
* 無加s表示單數，使用時會多帶入特定id → (order/{id})


## This
參考 : [鐵人賽：JavaScript 的 this 到底是誰？](https://wcc723.github.io/javascript/2017/12/12/javascript-this/)
### 關於一個函數中可以運用到的 “參數”
```javascript=
// 關於一個函數中可以運用到的 “參數”
    var a = '全域'
    function fn(params) {
      console.log(params, this, window, arguments);
      debugger;
    }
    fn('參數');
```
- debugger：除錯模式
- params：外部傳入參數
- this：目前是 window
- window：在 Global 裡面
- arguments：特殊參數，取出 params 或是 params 以外的參數，類陣列
> arguments，過去常用，現在少用，不是正式的結構是類陣列，類陣列提供較少的方法，使用上較不方便
### 在不同調用下的this變化
* 此處this指向obj
```javascript=
// 在不同的調用下的變化
    var obj = {
      name: '小明',
      fn: function(params) {
        console.log(params, this, window, arguments);
        debugger;
      }
    }
    obj.fn('參數');
```
- this 改變成當前的 object(obj)

### 為什麼會用到 this

#### 渲染2張卡片範例
```htmlmixed=
<div class="container">
    <div id="app"></div>
    <div id="app2"></div>
</div>
```
```javascript=
const Card = {
      el: '#app',
      template: `<div class="card">
        <div class="card-body">
          This is some text within a card body.
        </div>
      </div>`,
      render() {
        const dom = document.querySelector(Card.el);
        dom.innerHTML = Card.template;
      }
    };
    const Card2={
      ...Card,
    }
    console.log(Card.el, Card2.el);
    Card2.el = '#app2';
    Card.render();
    Card2.render();
```
- **渲染位置**：Card.el
**說明**：使用展開運算子，造成function render 裡的 ```Card``` 無法替換，Card 和 Card2 的 el 都會指向 #app(Card.el)，最後只渲染一個card
**解決作法**：Card.el 換成 this.el，改為指向各自的 el，就可渲染出兩個card
- Vue 中會以元件化開發，類似此卡片範例
- **使用this，可提高程式碼的重複可用性**

#### 卡片範例示意圖
- render 時，Card2 中的 render會指向 Card1 中的 el ( 指向同一 el )![](https://i.imgur.com/9DVMUFX.png)
- 使用this後，render時，會各自找自已的 el ![](https://i.imgur.com/o1hupJp.png)
- el：渲染的位置
- 代名詞的概念，this 就是我

#### 中樂透的特徵 - 不是Ray是財富自由Ray
- 吃都吃最好的，點最貴的
- 拿兩支手機
- 吃布丁都不舔封膜
- 𦾧條加大後不吃完，不拿糖醋醬

#### this 如何指向
```javascript=
    // This 的要點
    var someone = '全域變數'; // 請注意，這裡用的是 var
    function callSomeone() {
      console.log(this.someone);
    }
    callSomeone();
```
- 範例用 var 宣告全域變數
- 目前的 this 指向全域

#### this 的指向關鍵在「如何呼叫它」
> 呼叫函式的前一個“物件”，this會指向該物件
> (老師:也可以這樣理解)誰呼叫包含this的函式，this就是誰
```javascript=

    function callSomeone() {
      console.log(this.someone);
    }
    callSomeone();

    // This 指向關鍵在如何呼叫它，請注意呼叫函式的前一個 “物件”
    var obj = {
      someone: '物件',
      callSomeone() {
        console.log(this.someone); // A:物件
      }
    }
    obj.callSomeone();

    var obj2 = {
      someone: '物件2',
      callSomeone
    }
    obj2.callSomeone(); // A:物件2
```
- 調用 this 的程式碼，往前看，物件指向哪裡，this 就指向哪裡
- 不要看 this this 怎麼定義的，看它是怎麼被呼叫的

#### 無論幾層，都是看調用的前一個 “物件”
```javascript=
    // 無論幾層，都是看調用的前一個 “物件”
    function callSomeone() {
      console.log(this.someone);
    }
    callSomeone();
    var wrapObj = {
      someone: '外層物件',
      callSomeone,
      innerObj: {
        someone: '內層物件',
        callSomeone,
      }
    }
    wrapObj.callSomeone(); // A:外層物件
    wrapObj.innerObj.callSomeone(); // A:內層物件
```

### this 的目的
<!-- javascript=
    var newObj1 = {
      someone: '物件',
      callSomeone() {
        console.log('callSomeone:', this.someone);
      },
      callMethods() {
        // 請問如何在此觸發 callSomeone
        this.callSomeone(); //答案
      }
    }
    newObj1.callMethods();

- 上面這段 code 和 Vue 運作的情況一模一樣 -->

#### this 的目的是為了可以調用物件內的其它方法
> 此段 code 和 Vue 運作的情況一模一樣
```javascript=
var newObj1 = {
  someone: '物件',
  callSomeone() {
    console.log('callSomeone:', this.someone);
  },
  callMethods() {
    // 請問如何在此觸發 callSomeone
     this.callSomeone(); //答案
  }
}
newObj1.callMethods();
```
#### 執行的過程示意圖，呈現一層一層地往上跳 ![](https://i.imgur.com/AbaAuha.png) 

### 模擬Vue中的this運作

#### 如何取得 data 的值
```javascript=
    const newObj1 = {
      data: '物件',
      render() {
        // #2 如何取得 data 的值
        console.log(this.data); // ans
      },
      init() {
        // #1 請問如何在此觸發 render()
        this.render(); // ans
      }
    }
    newObj1.init(); //⚡⚡ this 指向 newObj1
```
#### 如何取得物件中元素的值
```html=
  <div class="container">
    <div id="app"></div>
  </div>
  ```
  ```javascript=
      const Card = {
      el: '#app',
      template: `<div class="alert alert-primary" role="alert">
        A simple primary alert—check it out!
      </div>`,
      render() {
        // 如何取得本物件 el
        const dom = document.querySelector('this.el'); // ans

        // 如何取得本物件 template
        dom.innerHTML = 'this.template'; // ans
      }
    };
    Card.render(); // ⚡⚡this 指向 Card
  ```
#### 在 Vue 裡面，this 會像上面這2個例子使用
 - 因箭頭函式和傳統函式的this指向不一樣，定義Vue的函式時，會使用傳統函式

### 箭頭函式
```html=
<div class="container">
    <div id="app"></div>
</div>
```
  
```javascript=
  var newObj1 = {
      someone: '物件',
      callSomeone() {
        console.log('callSomeone:', this.someone);
  },
  callMethods() {
        // 說明此段問題及修正
        // 修正方法 1. vm
        // 修正方法 2. arrow function
        // setTimeout(function () {
        //   this.callSomeone();
        // }, 100);
      }
  }
  newObj1.callMethods();
```
#### simple call
- **simple call 的 this 大部分指向 window**
- callback function 屬於 simple call
##### setTimeout
- 屬於callback function
- 在 setTimeout 事件中被執行時，看不出實際上this在哪裡被調用，這時候的 this 會特別危險
##### 補充this
- this都是在函式中生成，相同函式中的this都會指向同一個
#### 修正this指向
##### 方法1，先把 this 指定到變數 vm
![](https://i.imgur.com/ou0JO2j.png)

##### 方法2，setTimeout使用箭頭函式
* this 指向 newObj1
![](https://i.imgur.com/5j3AkFC.png)
看到箭頭函式時，這時候 this 會對應外層 callMethos 這個函式，**俗稱：箭頭函式沒有自已的 this**, 外層的作用域指向哪，它就指向哪
![](https://i.imgur.com/7lCtP1s.png)
- 初學：使用 vm
- 想精進，多觀察，助教推薦，用箭頭函式
- 可以試著這樣聯想： this 在 arrow function 中，是指向父層的 funciton，看外層被哪個作用域調用
- 再加一層 setTimeout ，結果一樣

### 如何操作物件中的陣列(⚡⚡實戰常見)
```htmlmixed=
  <div class="container">
    <div id="app"></div>
  </div>
```

```javascript=
    const newObj1 = {
      data: [],
      array: [1, 2, 3, 4, 5],
      callMethod() {
        // 請將所有數值 * 2，並儲存在 data 內
        this.array.forEach(function(item) {
          this.data.push(item);
        });
        console.log(this.data);
      }
    }
    newObj1.callMethod();
```

報錯，找不到 data 做 push
![](https://i.imgur.com/YLiAwAp.png)

把 forEach 裡的 function 改成 arrow function
![](https://i.imgur.com/Fnq8uC6.png)

⚡⚡simple call 在實戰中不會用到

### 陷阱題
#### var & const
> const定義的變數，不會在window下
- [jsfiddle](https://jsfiddle.net/ycst/Lafh2nbm/28/)
- [const 的作用域](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Statements/const)
![](https://i.imgur.com/nibobYW.png)


#### this 指向關係(跟著影片箭頭走一次)
問題8:
obj.myfn()執行後，myfn()的this指向obj，觸發myfn()後，this.fn()的this同樣指向obj，答案為「小明」
問題9:
setTimeout屬於simple call，通常this指向全域，全域有var宣告的myName變數，所以答案為「全域」
![](https://i.imgur.com/oq5Qzfj.png)


## This 與 Vue 的關係

```htmlmixed=
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="https://unpkg.com/vue@next"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.24.0/axios.min.js"></script>
</head>
<body>
  <div id="app">
    <ul>
      <li v-for="item in people">
        {{ item.email }}
      </li>
    </ul>
    <button type="button" v-on:click="getRandomUserData">取得遠端資料</button>
  </div>

  <script>
    // #1 說明 this 與 Vue 的關係
    // #2 v-on 如何觸發方法
    // #3 介紹生命週期如何觸發方法
    Vue.createApp({
      // 資料集合
      data() {
        return {
          people: [],
        }
      },
      // 方法集
      methods: {
        getRandomUserData() {
          axios.get('https://randomuser.me/api/')
            .then((res) => {
              console.log(res); 
              this.people = res.data.results
            }).catch((err) => {
              console.log(err.response);
            });
        }
      },
      // 生命週期
      created() {
        this.getRandomUserData();
      }
    }).mount('#app');
  </script>
</body>
</html>
```

### this 與 Vue 的關係
- Vue 裡的所有集合，都是物件型式，除data()資料集合外
-  data()資料集合，使用 function return 目的:
    - 為了 this 綁定正確
    - 可複用性
- 直接被執行的，用函式的型式，例如methods()生命週期

![](https://i.imgur.com/zHumvUF.png)

- mounted：元件建立時，會立刻執行它
- createApp：建立實體
- mount：指定一個位置，渲染上去
- 所有的實體都可以看成元件，元件分內層、外層
- methods 可以使用 this ， call 到 data 裡的資料

#### mounted

```javascript=
mounted() {
    console.log(this);
}
```
#### this 指向 Proxy 物件
> Vue3 雙向綁定都是透過 Proxy 物件做運行

![](https://i.imgur.com/mqU8uIl.png)

- 打開Proxy 物件後，在Target中能看到:
function(), data 都是 ...展開 的型式存放在內，**表示此處 this 可以互指**
![](https://i.imgur.com/Eig10Yo.png)
![](https://i.imgur.com/NvzGf4f.png)

- 原先資料放在 data()，方法放在 methods()，此時資料、方法都在各自的物件內，Vue 實體化的過程中，會把這些物件展開到Target中，變成 Target 中的型式(如下圖)
> 展開的情況下，資料可以互相指向
> ❌this.methods.fn()， ✔this.fn()

![](https://i.imgur.com/PyaQ8pX.png)

- EX:用 this.text 取得data()中 text 的內容
![](https://i.imgur.com/UYE8WGK.png)

#### methods方法集的觸發方式
1. 從mounted()生命週期中觸發
2. 從畫面上方法來觸發，ex:`v-on:click`
    - 使用 button，記得加 type="button"
    - v-on:click="getData"

##### 1.從mounted()生命週期中觸發，並取得遠端資料，存到data資料集
> [codepen參考](https://codepen.io/ldddl/pen/poWBJrK)
- Data() 裡，新增一個屬性名稱people，值為空陣列[]
- methods()，新增getData()方法，建立 axios.get()，取得遠端資料，並將遠端資料，利用 this.people，賦予到people中
- mounted()，呼叫 this.getData()

##### 2.從畫面上來觸發方法(v-on)
> [codepen參考](https://codepen.io/ldddl/pen/wvrZGEP)
* HTML上加上button，並用Vue元件v-on綁定methods方法名稱
> @ 為 v-on 縮寫
> getData 為 methods方法名稱

```
<button type="button" @click="getData">按我</button>
```

## 隨堂小考
- [第一系列](https://bejewled-air-4cb.notion.site/639c3dd5d18b4b54828f0792cae887d1)
- [第二系列](https://bejewled-air-4cb.notion.site/fe69c43e07a94b24bf5e26a6733561b2)
- [第三系列](https://bejewled-air-4cb.notion.site/0aa9e0be66d649b0a6443a2ccfe55be6)


## API 概念
###### tags: hex api
### 示意圖
![](https://i.imgur.com/9Pzxwaj.png)

- 必需上傳自已的圖片等內容
- 必需先把資料儲存到資料庫
- 前端 VUe
- 前端沒辦法直接跟資料庫溝通
- 需要伺服器和資料庫溝通
- 溝通的行為包括增、刪、修、查
- 溝通的過程稱為 **api**
- 請求，request
- 伺服器接收到請求後，才會向資料庫要資料，資料庫才會把資料以回應的方式，回傳給前端
- 回應，response
- 依據請求，給予不同的回應
- 請求成功或失敗有不同的回應
- get，查
- post，增
- put，修
- delete，刪

### 申請 Api
![](https://i.imgur.com/AL4v2qy.png)
- [課程 Api 申請](https://vue3-course-api.hexschool.io/)
- 申請 Api 路徑
- 路徑不符合，無法新增資料
- 測試 Api
    - 新增
    - 取得
- 每個人的 Api 都是獨立的

### 用戶分為2大類
![](https://i.imgur.com/wuUCFMQ.png)
- 管理控制台
    - 帳密先傳給伺服器
    - 伺服器檢查帳密是否正確
    - 正確的話，產生一組 token(像鑰匙)
    - 下一次前端不用再給密碼，給 token 就好
    - 伺服器確定是本人後，放行管理控制台的操作
    - 失敗結果可用 console.dir()查看![](https://i.imgur.com/SHncW9a.png)

- 客戶購物

### 使用 cookie
#### 儲存 token
- [MDN cookie](https://developer.mozilla.org/zh-CN/docs/Web/API/Document/cookie)
```javascript=
if (document.cookie.replace(/(?:(?:^|.*;\s*)someCookieName\s*\=\s*([^;]*).*$)|^.*$/, "$1") !== "true") {
  alert("Do something here!");
  document.cookie = "someCookieName=true; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/";
}
}
```
```javascript=
document.cookie = `hexToken=${ token }; expires=${ new Date(expired) };`;
```

#### 使用 token
把 test2 換成儲存的 token 名稱
```javascript=
const token = document.cookie.replace(/(?:(?:^|.*;\s*)test2\s*\=\s*([^;]*).*$)|^.*$/, "$1");
```

```javascript=
const token = document.cookie.replace(/(?:(?:^|.*;\s*)hexToken\s*\=\s*([^;]*).*$)|^.*$/, "$1");
```
#### axios 加入 hearder
- [axios](https://github.com/axios/axios)
- `axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;`

## 檔案上傳

#### 產品上傳 api
![](https://i.imgur.com/7Ww0WtT.png)
- 圖片檔案不會直接上傳

#### 圖片上傳 api
![](https://i.imgur.com/4bH1ega.png)
- 上傳圖片，大都用表單的形式做
    :::spoiler form 格式
    ```javascript=
    <form action="/api/thisismycourse2/admin/upload" enctype="multipart/form-data"  method="post">
    <input type="file" name="file-to-upload">
    <input type="submit" value="Upload">
    </form>  
    ```
    :::
- 因為表單有 type="file" 的格式，`input type="file"`
- input 內容
    :::spoiler input
    ![](https://i.imgur.com/lCWx83h.png)

    :::
- 上傳範例
    :::spoiler upload
    ```javascript=
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.21.1/axios.min.js"></script>
    </head>
    <body>

      <div>

      </div>

      <div>
        <input
          type="file"
          class="form-control"
          id="file"
          placeholder="請輸入圖片連結"
        />

      </div>

      <script>
      const url = ''; // 請加入站點
      const path = ''; // 請加入個人 API Path

      const fileInput = document.querySelector('#file');

      fileInput.addEventListener('change', upload);

      function upload() {
        // #1 撰寫上傳的 API 事件
      }

      </script>
    </body>
    </html>
    ```
    :::
- 上傳後從 console 看![](https://i.imgur.com/4SfbByI.png)
- 把檔案取出來
![](https://i.imgur.com/Yf8eRE8.png)
![](https://i.imgur.com/Ch6E2MB.png)

- 觀察 api 對應欄位
![](https://i.imgur.com/u81KVug.png)
![](https://i.imgur.com/YtIjCn1.png)

- 未登入進行上傳 ![](https://i.imgur.com/cX7Jk3X.png)
- 登入後成功上傳![](https://i.imgur.com/cAygFiN.png)

## ref
- [串接 api code 參考](https://github.com/stevecyj/vue-2022-api)
- [Document.cookie](https://developer.mozilla.org/zh-CN/docs/Web/API/Document/cookie)

## 其他
* 六角API使用的服務：[lambda serverless](https://aws.amazon.com/tw/lambda/)
    * 用途:伺服器流量過大時，Server的處理機制會自動加開伺服器來分散流量
(老師應該是這意思!?) 
    * [Day1 - Serverless 介紹](https://ithelp.ithome.com.tw/articles/10213431)


