# 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') }) } ``` 函式執行的先後順序如下,大概...? ![](https://i.imgur.com/uxLM4si.png) #### 更新上面的段落後續: 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)