改寫 Twitch 作業:把 XHR 改成 Fetch


XMLHttpRequest Syntax:
以下 code 改自
Using XMLHttpRequest

var oReq = new XMLHttpRequest();
oReq.addEventListener("load", () => {
   // do something
});
oReq.open("GET", URL, true);
oReq.setRequestHeader('Client-ID', clientIdHeader)
oReq.send();

主要指令:

  1. var oReq = new XMLHttpRequest();
  2. oReq.addEventListener("load", () => {})
  3. request.onerror =
  4. (oReq.setRequestHeader('Client-ID', clientIdHeader))
  5. request.send();
    原本的 XMLHttpRequest:
    // set variables
    const apiUrl = 'https://api.twitch.tv/kraken/'
    const acceptHeader = 'application/vnd.twitchtv.v5+json'
    const clientIdHeader = 'bmrryhsxxxxxxxxxxxxxxxxxxxxxxo'
    // start
    const requestNavBar = new XMLHttpRequest()
     requestStreams.addEventListener('load', () => {
       if (requestStreams.status >= 200 && requestStreams.status < 400) {
         const jsonStreams = getJsonForm(requestStreams)
         updateLiveStreams(jsonStreams, streamsNumber)
       } else {
         console.log(requestStreams.status, requestStreams.responseText)
       }
     })
     requestStreams.onerror = () => {
       console.log('error')
     }
     requestStreams.open('GET', `${apiUrl}streams?stream_type=live&game=${topFiveGames[0]}`, true)
     requestStreams.setRequestHeader('Accept', acceptHeader)
     requestStreams.setRequestHeader('Client-ID', clientIdHeader)
     requestStreams.send()
    
    修改成 fetch 形式:
    const apiUrl = 'https://api.twitch.tv/kraken/'
    const acceptHeader = 'application/vnd.twitchtv.v5+json'
    const clientIdHeader = 'bmrryhsxxxxxxxxxxxxxxxxxxxxxxo'
    url = `${apiUrl}streams?stream_type=live&game=${topFiveGames[0]}`
     fetch(url, {
       method: 'GET',
       body: JSON.stringify(data),
       headers: {
         'Client-ID': clientIdHeader,
         'Accept': acceptHeader
       },
     })
    

作業名稱

week 13 hw3 twitch API 改寫

碰到的問題一

How to get data returned from fetch() promise?

碰到問題

在 dev tool 查看 network 上的 API 有 GET 到,但是 console 欄沒有印出值。

enter main
result: undefined

預期的行為

印出 data。

enter main
result {_total: 2426, top: Array(5)}

嘗試過的解決方法

擷取自How to get data returned from fetch() promise?

如果在 fetch 最後面加上 .then(data => {console.log(data)) 就可以印出 API 資料,但是在 getData() 之外執行 getData(),就取不到資料,會顯示 undefined。

相關程式碼

const sleep = ms => new Promise(resolve => {
      setTimeout(resolve, ms)
    })

function getData() {
      api200 = 'https://run.mocky.io/v3/0801540d-ad87-4a2f-a5c4-abfb25463ccb';
      fetch(api200)
        .then((response) => {
          return response.json()
        })
    }

    async function main() {
      console.log('enter main')
      await sleep(1000)
      const result = await getData() //回傳 promise
      console.log('result', result)
    }

    main()

思考過程

沒有細看 console 出來的訊息「undefined」,在 function 執行後產生的意思,其實是在 function 內沒有 return 值,所以在 function 被執行時,會印出 undefined。
後來在 fetch(api200) 改成 return fetch(api200) 就印出來 array 了,後來發現 return response.json() 是在 .then(function) 內的 return 不是在 getData() 的回傳值,所以才會印出 undefined。


碰到的問題二:

What is the difference between JavaScript promises and async await?

碰到問題

dev tool: console

Promise {<pending>}
__proto__: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: Object

預期的行為

dev tool: console

{_total: 2392, top: Array(5)}
    top: (5) [{…}, {…}, {…}, {…}, {…}]
    _total: 2392
    __proto__: Object

嘗試過的解決方法

相關程式碼

function getData() {
  return fetch(url, {
    method: 'GET',
    headers: new Headers({
      'Accept': acceptHeader,
      'Client-ID': clientIdHeader
    })
  }).then((response) => {
    return response.json();
  })
}


async function getTop5Games() {
  const result = await getData(); //回傳 promise
  return result;
}
console.log(getTop5Games());

修改:

async function getTop5Games() {
  const result = await getData(); //回傳 promise
  console.log(result);
}
getTop5Games()

思考過程

async function--MDN 回傳的是 promise,所以可以發現在第一部份出錯時,在 async function getTop5Games return 的是 result 變數,然後再印出來:Promise {<pending>}


碰到的問題三:

要如何使用 try catch 的方法,才可以抓出錯誤訊息?以下嘗試了三個方法:

碰到問題

預期的行為

預期只是想測試 API URL 有無錯誤,沒有的話,就繼續往下執行 code。

嘗試過的解決方法

嘗試的解決方法有以下:

  1. [Failed] 方法一:在 try 放 URL,fetchtry catch 之外
  2. [Failed] 方法二:在 try catch 後加上 finally { fetch =>得到 API data}
  3. [successed] 方法三:在 try 放入要執行的 code,在最後放 catch error
    ##### 嘗試過的解決方法一:
    將變數命名拉出來,只在 try 裡面放 API URL(如下圖及 code),並輸入錯誤的 API URLhttps://apis.twitch.tv/kraken/games/top?limit=${topGameNumber}(正確為 api.twitch...,我在 api 後面多加 s,變成錯誤的 API URL)。
輸出結果:

顯示的 error 提示,是在 fetch 裡面印出的的錯誤訊息提示,不是 try catch 印出的。

相關 code:
async function getNavAndStreams() {
  const navBarUrl = `https://apis.twitch.tv/kraken/games/top?limit=${topGameNumber}`
  try {
    navBarUrl
  } catch (err) {
    console.log('error in the home page:\n', err)
  }
  const jsonData = await getData(navBarUrl) // GET API: 前五熱門的遊戲 data
嘗試過的解決方法二:

查 MDN 裡 finally 的方法,使用看看,將略過 try catch 的內容,先行執行的 finally 指令放入使用 fetch 發 request 得到 API 的 code。

輸出結果:

還是找不到 jsonData 的值。結果下圖就出現: undefined 看不懂被 try 包住的變數 jsonData,然後想起來變數的 scope 特性:外層看不到內層的變數,內層看的到外層的變數。

相關 code:
  const navBarUrl = `https://api.twitch.tv/kraken/games/top?limit=${topGameNumber}`
  try {
    navBarUrl
  } catch (err) {
    console.log('error in the home page:\n', err)
  } finally {
    const jsonData = await getData(navBarUrl) // GET API: 前五熱門的遊戲 data
  }
...
嘗試過的解決方法三:

將需要執行的 code 全部包進 try,最後再 catch(err) {console.log(err)} 錯誤。
輸出結果:將 API 故意輸入成錯誤的 API(https://api.twitchssss.tv...) 顯示如下圖:

輸出結果:

相關 code:
  try {
    const navBarUrl = `https://api.twitch.tv/kraken/games/top?limit=${topGameNumber}`
    const jsonData = await getData(navBarUrl) // GET API: 前五熱門的遊戲 data
    const topFiveGames = await topGamesList(jsonData, topGameNumber) // array(length= 5):前五熱門遊戲名稱的
    await dynamicUpdateNavBar(topFiveGames) // JS動態新增到 HTML:導覽列的前五熱門遊戲名稱
    await dynamicUpdateH2(topFiveGames) // JS動態新增到 HTML:首頁最熱門遊戲的名稱(heading 2)

    // 首頁:20 個實況
    const top1StreamsUrl = `${apiUrl}streams?stream_type=live&game=${topFiveGames[0]}` // 準備發 request 的 URL,目的為尋找該遊戲的前20實況台
    const jsonStreams = await getData(top1StreamsUrl) // GET API 該遊戲的前 20 實況台資料
    await updateLiveStreams(jsonStreams, streamsNumber) // JS動態新增到 HTML:前 20 實況台資料
  } catch (err) {
    console.log('error in the home page:\n', err)
  }

相關程式碼:尚未加入 try catch 前的 code

async function getNavAndStreams() {
  // 首頁:從 API 抓取前五熱門遊戲名稱及 top 1
  // 並新增至 navbar 與 top 1 遊戲名稱(heading 2)
    const navBarUrl = `https://api.twitch.tv/kraken/games/top?limit=${topGameNumber}`
    const jsonData = await getData(navBarUrl) // GET API: 前五熱門的遊戲 data
    const topFiveGames = await topGamesList(jsonData, topGameNumber) // array(length= 5):前五熱門遊戲名稱的
    await dynamicUpdateNavBar(topFiveGames) // JS動態新增到 HTML:導覽列的前五熱門遊戲名稱
    await dynamicUpdateH2(topFiveGames) // JS動態新增到 HTML:首頁最熱門遊戲的名稱(heading 2)

    // 首頁:20 個實況
    const top1StreamsUrl = `${apiUrl}streams?stream_type=live&game=${topFiveGames[0]}` // 準備發 request 的 URL,目的為尋找該遊戲的前20實況台
    const jsonStreams = await getData(top1StreamsUrl) // GET API 該遊戲的前 20 實況台資料
    await updateLiveStreams(jsonStreams, streamsNumber) // JS動態新增到 HTML:前 20 實況台資料

碰到的問題四:

new Promisefetch 的關聯?要如何一起使用?

問題描述:

因為在影片範例中提到怎麼自己建立一個 promise,加上也有提到是要將作業 twitch 的 XHRHttpRequest 改成 fetch,還要改成使用 promise,所以一開始我在想要怎麼在作業裡面使用到這兩個方法。

疑惑解答:

但是不太瞭解要怎麼使用,所以查到以下這個資料:

  1. What about "new Promise"? What is it? Do I need it? When?

    You need it when you don't have a promise already and you need a promise chain. You don't need it when you have a promise already (such as the one from fetch) and need a promise chain.
    From:(JS) Very confused about Promises with fetch

碰到的問題四:

How to Use Fetch with async/await?

問題描述:

要怎麼使用 async/await 來實現非同步的方法?

疑惑解答:

How to Use Fetch with async/await? 這篇文章的範例,觀察到 fetch 與使用 async/await 的方法:

  1. Summary
    Calling fetch() starts a request and returns a promise. When the request completes, the promise resolves to the response object. From the response object you can extract data in the format you need: JSON, raw text, Blob.
    Because fetch() returns a promise, you can simplify the code by using the async/await syntax: response = await fetch().
    From: How to Use Fetch with async/await?

,加上在How to make HTTP requests using Fetch API and Promises 提到了 promise 的意思,執行過程為非同步,替代了使用 callback function 來執行非同步的方式:

What are Promises?
The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
Promises provides us a simpler alternative to executing, composing and managing asynchronous operation compared to the traditional callback-bases approach.
From: How to make HTTP requests using Fetch API and Promises

有了怎麼使用 fetch, await, asyncpromise 的概念,就知道要怎麼寫了,嘗試如下:

async function getNavAndStreams() {
  // 首頁:從 API 抓取前五熱門遊戲名稱及 top 1
  // 並新增至 navbar 與 top 1 遊戲名稱(heading 2)
  try {
    const navBarUrl = `https://api.twitchssss.tv/kraken/games/top?limit=${topGameNumber}`
    const jsonData = await getData(navBarUrl) // GET API: 前五熱門的遊戲 data
    const topFiveGames = await topGamesList(jsonData, topGameNumber) // array(length= 5):前五熱門遊戲名稱的
    await dynamicUpdateNavBar(topFiveGames) // JS動態新增到 HTML:導覽列的前五熱門遊戲名稱
    await dynamicUpdateH2(topFiveGames) // JS動態新增到 HTML:首頁最熱門遊戲的名稱(heading 2)

    // 首頁:20 個實況
    const top1StreamsUrl = `${apiUrl}streams?stream_type=live&game=${topFiveGames[0]}` // 準備發 request 的 URL,目的為尋找該遊戲的前20實況台
    const jsonStreams = await getData(top1StreamsUrl) // GET API 該遊戲的前 20 實況台資料
    await updateLiveStreams(jsonStreams, streamsNumber) // JS動態新增到 HTML:前 20 實況台資料
  } catch (err) {
    console.log('error in the home page:\n', err)
  }
}

碰到的問題五:

箭頭函式簡化

問題描述:

疑惑解答:

pros and cons

#fetch #Promise #javascript







你可能感興趣的文章

OAuth2.0 三部曲(3) - OPENID CONNECT(OIDC) 身分認證機制

OAuth2.0 三部曲(3) - OPENID CONNECT(OIDC) 身分認證機制

【THM Walkthrough】Breaching Active Directory

【THM Walkthrough】Breaching Active Directory

程式設計共學營學員回饋心得

程式設計共學營學員回饋心得






留言討論