/JavaScript, ES6

JavaScript | Fetch 讓 ES6 擁有一對翅膀-基礎教學

前言

「使用 Jquery 框架中的 Ajax 就能輕鬆做到了!」

莫約幾年前,在 ES6 已推出卻又還沒有普及的時候,如果有人提到:「如何用 JavaScriptserver 請求資料?」,一定會有人這麼留言回答。

沒錯! $.ajax 幾乎是最簡單又容易上手的請求方式了,不只在底層做了許多處理,也不必再向原生 JavaScript 中又臭又長的 XMLHttpRequest() 請求物件低頭,甚至還幫忙處理了同步執行的模式,使用起來就像這樣:

$.ajax({
    type: 'get',
    url: 'https://httpbin.org/get',
    success: result => {
        console.log(result)
    }
})

看起來很棒!對吧?但那都是幾年前了。

模組化(NPM & Module)

近年前端工程在網頁上越來越吃重,投入前端框架的開發者(Developer)變多,讓以前一黨獨大的 JQuery 開始被多個許多小功能的框架給取代,因為 JQuery 擁有太多網站中用不到的 function ,但他們依然會被載入到網頁中。

面臨上述供給大於需求的情況,許多人便紛紛選擇只擁有自己需要功能的小框架,減少在 Client 端載入過多多餘的程式碼。

這些趨勢間接讓撰寫原生 JavaScript 的人直線增長,從 ES6 開始出現的 PromiseClass 許多新原生的語法出現,終於有一天, XMLHttpRequest() 請求開始走入歷史了(或是根本沒人認識他XD)…


Fetch

FetchES6 的新語法,主要是搭配 PromisePromise 的基本用法)來執行請求網站和請求後獲取 Response 的處理方式。

以下範例的請求都會從 httpbin.org 這個網站裡挑選,它提供了各種不同的請求方式,在練習時是個很棒的工具。

GET

GET 是請求中最基本的類型,在 Fetch 中預設的請求類型也是 GET 用起來就像下方:

fetch('https://httpbin.org/get')
    .then((response) => {
        console.log(response)
        return response.json()
        //return response.text()
    }).then((myJson) => {
        console.log(myJson)
    })

Fetch 接收了一個 url 作參數,並用 then 接收此次請求的相關資訊:

關於該次請求的 response 內容

資訊內包含了請求的 url 和用來判斷請求是否成功的 status 狀態等,在 response 中有兩個內建函式可以用來得到請求回傳的資料。

一個是上方 thenreturn 使用的 .json() ,能夠將回傳的資料以物件的方式傳給第二個 then 接收,另一個是 .text() ,當回傳的資料無法轉換為物件時,則會將請求資料以字串方式取出。

下方為第二個 .thenconsole 中印出的 myJson 內容,以及當使用 .text() 時的資料模樣:

用 .json() 將 response 的請求資料取出

用 .text() 將 response 的請求資料取出

POST

GET 不同的是,使用 POST 請求時需另外在 method 屬性內指定 POST 方式,且多了 body 屬性指定要送出的資料:

fetch('https://httpbin.org/post', {
    method: 'POST',
    body: JSON.stringify(
        {
            name: 'GQSM',
            age: 25
        }
    )
}).then((response) => {
    return response.json()
}).then((myJson)=>{
    console.log(myJson)
})

Fetch 在未指定請求方式的情況下都是使用 GET ,但是 GET 本身無法在請求中藉由 body 送出資料,因此在有 body 屬性的狀態下,未替 method 指定為 POST 或其他可帶 body 的請求方式時,會出現以下錯誤:

預設的請求方式 GET 無法指定 body

需要注意的是, body 內的資料需使用 JSON.stringify 將物件轉換成字串型態,否則 server 端會無法正確取得資料,以下是 data 送進 server 的差別:

未使用 JSON.stringify

使用了 JSON.stringify

未使用 JSON.stringify 的請求會直接將物件強制轉為字串,變成 [object Object] 送至 server ,使用了正確轉換的請求在 server 端則是能接收到正確的內容。

請求失敗

Fetch 中,請求失敗時不會有像 $.ajax 中有 error 可以直接捕捉,取而代之的是要以 responsestatus 的屬性值判斷,當 status 的值不等於 200 時,將在 .then 中使用 throw 創建一個錯誤,並由 .catch 接收錯誤內容處理:

fetch('https://httpbin.org/status/500', {
}).then((response) => {
    if(response.status !== 200)
        throw new Error(response.status)
    return response.json()
}).then((myJson) => {
    console.log(myJson)
}).catch((error) => {
    console.log(`錯誤代碼為${error}`)
})

本文介紹了 Fetch 的基本用法及請求錯誤時的捕捉方式,雖然寫起來未必比 $ajax 還要簡單,但是從此以後也多了不需掛載 JQuery 轉為使用原生請求的選擇,唯一需要考量的是 FetchPromise 在瀏覽器上的支援度還太低,當換到 IE 時便完全無法使用。

不過就如前言所說的,目前投入前端框架的開發者有太多了,將來也會介紹筆者目前對處理請求使用的框架 axiosaxios 的使用方式和 Fetch 大同小異,在不考慮 Promise 的情況下,大幅度提高了瀏覽器的支援性,至少在 IE11 上也變得能夠使用,有興趣可以先至 GitHub 上查看文檔

如果以上內容有任何問題,或是不理解的地方,都歡迎留言告訴我,謝謝大家!

參考文章

  1. https://developer.mozilla.org/zh-TW/docs/Web/API/Fetch_API/Using_Fetch#Body
  2. https://wcc723.github.io/javascript/2017/12/28/javascript-fetch/