# Fetch 與 Promise 補充
###### tags:`Frontend`
[TOC]
發 ajax 的唯二種方法
* ==XMLHttpRequest==, XML
* ==Fetch==,( promise 讓 ajax 有更好的縮排/閱讀/ chaining 效果)
## Fetch 發 GET
```javascript=
fetch('url').then(cb).then(cb2).....
// GET method, return Promise obj > 要用 .then() 來拿/回傳資料
// .fetch() .json() .text() .then() => 預設 return promise type
```
## Fetch 錯誤處理
這裡說的錯誤不是 5xx 那種,而是連 response 都沒有拿到(tab 看不到)
```javascript=
.catch()
```
## Fetch 發 POST
```javascript=
fetch('url', {
method: 'POST',
body: ,
headers: new Headers({ // 不直覺
'Content-Type': 'application/json'
})
})
```
## Fetch Notice
* ==content type== 和 資料要相符,不要圖文不符
* mode: 'no-cors' // 不是指可以 cors, 而是指 cors 錯誤提醒不要跳出來
* 如果想要使用常用的`try...catch` 的話,要搭配`async/await`才可以達成
* fetch 的非同步除了串接 api (開頭就使用`fetch()`)之外,之後的 `.then()` 如果也想要確保先後順序的執行,就要確保`.then()`之間傳送的是 ==promise 物件==才行,單純用`.then()`包住是不會確保執行先後順序的(相當於 then() 不存在)!! 重要,這個我超容易忘記。但如果`.then()`放的是函式,要如何確保有 promist 物件被 return 呢?=> 詳見**Promise**
## ==小心那塊餅乾!==
cookie 的常見屬性,有些是在 Headers做設定
* `credentials: omit/same-origin/includes`,cookie 是否可以 cors
* `httpOnly: true`,cookie 只能用來做 request,不能在用戶端透過 document 來存取,避免 XSS
* `secure`,Cookie只能透過https的方式傳輸
* `Access-Control-Allow-Origin`,Headers,設定誰可以 cors
## Promise
Promise 是一個==物件==,通常用來處理==非同步==操作。
```javascript=
function init(resolve, reject) {
resolve(3) //預設的回傳
reject(5) // 發生錯誤(用 .catch() 接)的回傳
// 兩者同時出現的話也只有一個會被執行到
}
const myPromise = new Promise(init) // 給他一個 cb
myPromise.then(data => {
console.log('data', data) // 3
}).catch(err => {
console.log('err', err) // 5
})
```
其實`.then()`可以接收兩個參數,`promise.then(resolveCallback, rejectCallback)`,只是一般都用`.then()`處理成功,用`.catch()`處理失敗。
### ==Promise 也可以用來判斷動態新增是否結束==
```javascript=
function appendStreamsPromise(json, clearStreams = true) {
const streams = document.querySelector('.streams')
if (clearStreams) streams.innerHTML = '' // 點選別的遊戲之後,原本的內容要清空再載入別的遊戲的實況
for (const each of json.streams) {
const template = document.createElement('template')
template.innerHTML = htmlTemplate
.replace('$previewLarge', each.preview.large)
.replace('$channelLogo', each.channel.logo)
.replace('$channelStatus', each.channel.status)
.replace('$channelName', each.channel.display_name)
streams.append(template.content)
}
return new Promise((resolve) => {
resolve('append finished')
})
}
```
## async 與 await
await 後面要接 promise obj 才有效果
錯誤處理可以用 try catch
```javascript=
async function main() {
console.log('enter main')
const result = await sleep(1000)
console.log('exit main')
}
```
### 舉個例子
```javascript=
getTopGame(init)
function getTopGame(init) {
const url = `${baseUrl}/games/top?limit=5`
fetch(url, init)
.then((response) => response.json())
.then((data) => {
for (const each of data.top) {
topGameArr.push(each.game.name)
}
appendGames()
getStreams()
appendNav()
})
}
function getStreams() {
const url = `${baseUrl}/streams/?game=${game}&limit=${limit}&offset=${offset}`
fetch(url, init)
.then((response) => response.json())
.then((data) => {
return appendStreamsPromise()
})
.then((data) => {
console.log(data) // "append finished"
removeLoader()
})
}
function appendStreamsPromise() {
const streams = document.querySelector('.streams')
for (const each of json.streams) {
const template = document.createElement('div')
streams.append(template)
}
return new Promise((resolve) => {
resolve('append finished')
})
}
```
函式執行的先後順序如下,大概...?

#### 更新上面的段落後續: async/await 的寫法
```javascript=
run()
async function getTopGame(init) {
const url = `${baseUrl}/games/top?limit=5`
const response = await fetch(url, init)
const data = await response.json()
for (const each of data.top) {
topGameArr.push(each.game.name)
}
}
async function run() {
await getTopGame(init)
appendGames(topGameArr[0])
appendNav(init, topGameArr)
const data = await getStreams(init, topGameArr[0])
const resolve = await appendStreams(data, true)
console.log(resolve)
removeLoader()
}
```
**重要**
第 3 行是一個 async 函式,第 12 行也是個 async 函式,把第 3 行的函式丟到第 12 行的函式來去執行,目的是讓非同步的`getTopGame`,除了函式裡面的程式碼以外,在函式外面也有非同步的效果,我覺得就是 callback 的變形寫法
> 參考資料:[JavaScript Promise 全介紹](https://wcc723.github.io/development/2020/02/16/all-new-promise/)
> [Async function / Await 深度介紹](https://wcc723.github.io/development/2020/10/16/async-await/)
> [Week13 自我檢討](https://github.com/Lidemy/mentor-program-5th/tree/master/examples/week13)