(Day26) 使用 fetch 串接 Ajax

前言


fetch 是 JavaScript ES6 新增的用來執行 Ajax 行為的方法,相比舊版的 XMLHttprequest 不論是閱讀程式碼、或是實際開發都方便不少,而 fetch 其實就是使用 Promise 開發的方法,因此 fetch 語法和 Promise 寫法非常類似,同時可以使用到上個章節提到的 async/await

本篇會使用 https://randomuser.me/ 來做 ajax 範例。

fetch 基本介紹


要使用 fetch 直接使用 fetch() 並帶上網址便可執行 Ajax 行為,上面有提到 fetch 其實就是使用 Promise 開發的方法,因此當 fetch 的 Ajax 成功後,會使用和 Promise 相同使用 .then() 來執行成功的程式碼,失敗則是使用 .catch() ,比如這個範例:

1
2
3
4
5
6
7
8
9
fetch('https://randomuser.me/api/')
.then((response) => {
// 回傳 ReadableStream 物件,可使用 .json() 等等方法,取得對應資料。
return response.json()
}).then((data) => {
console.log(data)
}).catch((err) => {
console.log('錯誤:', err)
})


fetch 成功後,會回傳 ReadableStream 物件,這時會使用不同的方法取得對應資料,上面範例就使用 json() 來將 ReadableStream 轉換成一個實際可使用的物件, 其他方法還有:

  • json()
  • text()
  • bolb()
  • arrayBuffer()
  • redirect()
  • clone()
  • error()

詳細部分可參考 MDN 文件介紹:https://developer.mozilla.org/zh-TW/docs/Web/API/Response
上面也有提到 fetch 也可以搭配 async/await ,以上面範例來製作 async/await 版本:

1
2
3
4
5
6
7
8
9
10
async function useAjax() {
try{
const ajax = await fetch('https://randomuser.me/api/');
const data = await ajax.json();
console.log(data)
} catch(error) {
console.log('錯誤:', err)
}
}
useAjax()

如何設定 fetch


在實做中 Ajax 行為往往不會向上面範例這麼簡單,通常還需要設定一些 headersmethods 等等的設定,若要設定這些功能會在 fetch() 中第二個參數做詳細設定,而第二個參數必需寫成物件,比如這個範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
fetch('http://httpbin.org/post', {
// Ajax 行為改為 Post
method: 'POST',
// headers 加入 json 格式
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
test: '123',
})
})
.then((response) => {
return response.json()
}).then((Data) => {
console.log(Data)
}).catch((err) => {
console.log('錯誤:', err)
})


值得一提的是,使用 post 行為時 ,我們通常會帶上一些資料給後端,和其他包裝好的 Ajax 框架不同, fetch 會需要手動將資料轉成字串。

fetch 搭配 async/await 範例


在實做中一定會碰到需要有順序的執行 Ajax 的狀況,而這邊也模擬一些狀況,使用 fetch 做 Ajax 串接,並搭配前幾個章節介紹的 async/awaitPromise.all() 來製作可以按順序來執行 Ajax 的程式碼:

  • 狀況一:需等 Ajax1 完成後,才執行 Ajax2

    這種狀況使用 async/await 或是 原生 Promise 鏈式寫法都能達成,這邊以 async/await 為範例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    async function useAjax() {
    try {
    const ajax1 = await fetch('https://randomuser.me/api/')
    const data1 = await ajax1.json()
    console.log('data1', data1)
    const ajax2 = await fetch('https://randomuser.me/api/')
    const data2 = await ajax2.json();
    console.log('data2', data2)
    } catch (error) {
    console.log('錯誤:', err)
    }
    }
    useAjax()
  • 狀況二: 需等 Ajax1、Ajax2 完成後,才執行 Ajax3

    這種狀況其實繼續使用 async/await 來寫也可以達成,不過會變成:

    執行 Ajax1 ⇒ Ajax1 完成 ⇒ 執行 Ajax2 ⇒ Ajax2 完成 ⇒ 執行 Ajax3

    這樣就會浪費較多時間再等待 Ajax 回傳,所以比較好的方法就是使用 Promise.all() 搭配 async/await ,或是單純 Promise.all() 加上 Promise 鏈式寫法,這邊以 Promise.all() 搭配 async/await 為範例。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    async function useAjax() {
    try {
    const ajax1 = fetch('https://randomuser.me/api/')
    const ajax2 = fetch('https://randomuser.me/api/')
    const [res1, res2] = await Promise.all([ajax1, ajax2])
    const data1 = await res1.json()
    const data2 = await res2.json()
    console.log('data1', data1)
    console.log('data2', data2)
    const ajax3 = await fetch('https://randomuser.me/api/')
    const data3 = await ajax3.json()
    console.log('data3', data3)
    } catch(error) {
    console.log('錯誤:', err)
    }
    }
    useAjax()

    參考文獻

  • 鐵人賽:ES6 原生 Fetch 遠端資料方法
  • MDN 文件 - fetch