3 - 非同步之認識 fetch


Posted by backas36 on 2021-07-21

之前介紹完 Promise 了,不能違背我的標題, fetch 當然也要講,而且 fetch 才是重頭戲,談 fetch 就一定要談 async 和 await 囉。

如果覺得頭尾接受不上可以看一下前兩篇文章,這邊會直接從 fetch 開始,真的看不懂的話建議是從第一篇開始看,因為有先介紹 XMLHttpRequest 再循序漸進的來這邊的,再真的不懂的話,那代表我寫得不好😣。

直接切入重點吧:

const api200 = 'https://run.mocky.io/v3/98c6ea3a-2359-429d-8be1-98396934af0f'
// 完全正常運作的 server

const api500 = 'https://run.mocky.io/v3/bf2b926c-0db4-4f98-b09a-1211d4da6038'
// 假裝 server error 回傳 500 的 api

const apiJsonError = 'https://run.mocky.io/v3/3bf6bbd8-6b7c-47f7-8b92-9efb2a0a8dfc'
// 回傳 200 但是 json 格式錯誤的 api

const apiWrongUrl = 'https://srun.mocky.io/v3/98c6ea3a-2359-429d-8be1-98396934af0f'

const apiUser = 'https://reqres.in/api/users'

console.log(fetch(api200))

此時你會看到 console.log(fetch(api200)) 會回傳 Promise {<pending>},記得,看到 Promise 就是要用 then, 看到 Promise 就是要用 then, 看到 Promise 就是要用 then 。

 fetch(api200)
  .then(response => {
    return response.json() //回傳一個 Promise
  }).then(data => {
    console.log(data) // 成功拿到資料
  })

拿到 response之後,如果直接 console.log(response) 是拿不到資料的,因為這個 response 還是我們要的回傳內容,這個 response 裡面的屬性 response.okresponse.status ... 等。
如果要拿到我們要的回傳內容要再加上 .json() 變成 response.json() 來解析,如果你不是 return response.json() 而是直接 console.log(response.json()) 會再次得到 Promise,因為 response.json() 會回傳一個 Promise,所以一樣,看到 Promise 就是要, then !
接著就可以把 data 拿到了!

身為一個準前端工程師,我們還是要謹慎的來處理錯誤訊息,雖然我自己對於這塊真的很不熟,有好心人士的話可以來糾正我沒關係。

fetch(apiJsonError)
  .then(response => {
    return response.json() 
  }).then(data => {
    console.log(data) 
  })
  .catch(error => {
    console.log(error) // apiJsonError,apiWrongUrl 都會執行這邊
  })

接著帶入一些會發生錯誤的API URL 試試看(可以參考一下文章最上面的那個程式範例),可以發現只有 apiJsonError,apiWrongUrl。
這邊可以看一下 MDN Using Fetch

fetch() 回傳的 promise 不會 reject HTTP 的 error status,就算是 HTTP 404 或 500 也一樣。相反地,它會正常地 resolve,並把 ok status 設為 false。會讓它發生 reject 的只有網路錯誤或其他會中斷 request 的情況。

所以假設我們帶入 api500 ,是回傳 HTTP 500,也就是會進入 reslove 階段,所以我們還要自己利用 repsonse.ok 來判斷一下,這樣才是正解!

fetch(api500)
  .then(response => {
    if (response.ok) {
      return response.json()
    }
    throw new Error('HTTP 500/400 Error') //api500的錯誤丟給 catch 接
  }).then(data => {
    console.log(data)
  })
  .catch(error => {
    console.log(error) // apiJsonError,apiWrongUrl 都會執行這邊
  })

基本就是要記得 fetch 和 then 之後的 response.json() 都是回傳 Promise,既然是 Promise ,所以我們要用 then 去接收。(你可以想成因為是 Promise ,所以 fetch 會自動幫我們處理好 resolve 和 reject 的過程,我們就可以直接 .then .catch 去接收 resolve 和 reject 的 回傳值。)

我們也可以使用 fetch Promise chainning 的方式連續串多個 API ,例如:

fetch(api200)
  .then(response => {
    if (response.ok) {
      return response.json()
    }
    throw new Error('HTTP 500/400 Error') //api500的錯誤丟給 catch 接
  }).then(data => {
    console.log(data)
    return fetch(apiUser)
  })
  .then(response => {
    if (response.ok) {
      return response.json()
    }
    throw new Error('HTTP 500/400 Error')
  })
  .then(data => {
    console.log(data)
  })
  .catch(error => {
    console.log(error) // apiJsonError,apiWrongUrl 都會執行這邊
  })

這樣我們就可以連續使用 fetch 來串好幾個 API,並且只要使用一個 catch 就可以接收那些 Promise reject 回傳的東西;但是整個程式碼有一堆的 return 再一堆 then,看起來還是不夠簡潔,下一篇也是這系列的最後一篇會來介紹解決這個問題的 async。

前面兩篇主要是先介紹 Promise,本來想只是想用筆記的方式記錄就好,但因為實在太不熟悉這非同步系列的東西,覺得之後自己可能會忘記就當作練習寫文章囉!

最後一篇來介紹 fetch 和 async & await 怎麼一起使用....,程式碼會更加簡潔唷!
1 - 非同步之認識Promise
2 - 非同步之Promise串 API
3 - 非同步之認識 fetch
4 - 非同步之認識 async/await


#非同步 #javascript #fetch







Related Posts

 ASI 自動分號插入

ASI 自動分號插入

Day 91

Day 91

漫談傳輸介面-PCI

漫談傳輸介面-PCI


Comments