fetch 方法到底取得的東西是什麼?

更新日期: 2024 年 10 月 30 日

在進行非同步網路請求時,fetch 是一個強大且靈活的工具。

使用 JavaScript 發送 HTTP 請求時,可以利用 fetch 來取得伺服器的資料。

但對初學者來說,fetch 究竟回傳了什麼?如何在 .then() 中使用這些回傳的內容?讓我們來釐清這些概念。

閱讀本文前,建議具備相關概念:初學者指南:了解 JavaScript 的 Promise 物件

fetch 回傳的內容:一個 Promise

當我們呼叫 fetch(api) 時,它會立即回傳一個 Promise 物件

在 JavaScript 中,Promise 是用來處理非同步操作的一種機制,通常用於在資料取得後進行後續處理。

fetch 回傳的 Promise 並不會直接傳回 API 的資料,而是會在請求成功時自動 resolve 成一個 Response 物件,其中包含了請求結果的詳細資訊。

基本的 Promise 與 resolve 概念

在深入理解 fetchPromise 之前,先掌握 resolve 的基本概念會對理解更有幫助。

當一個 Promise 被「resolve」時,它會將「resolve 時提供的資料」傳給 .then()

具體來說:

  • 當呼叫 resolve 時,可以提供任意資料作為 Promise 完成後的結果(例如字串、數字、物件,甚至是另一個 Promise)。
  • 這些資料會被傳遞到 .then() 中 callback 函數的第一個參數,以供後續處理。

resolve 的範例

以下範例展示了 Promise 被 resolve 時,如何將資料傳遞給 .then()

const myPromise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("Data from the asynchronous operation"); // resolve 傳遞這個字串
    }, 1000);
});

myPromise.then(result => {
    console.log(result); // 顯示 "Data from the asynchronous operation"
});

在這個例子中:

  • setTimeout 完成後,resolve("Data from the asynchronous operation") 被呼叫,使 Promise 狀態變為「已完成 (fulfilled)」。
  • resolve 傳入的字串 "Data from the asynchronous operation",會作為結果傳給 .then(result => {...}) 中的 result 參數,並在控制台輸出。

Response 物件是什麼?

這個 Response 物件包含了伺服器回應的詳細資訊,如:

回到 fetch,當它的 Promise 被 resolve 時,並不會直接返回資料,而是返回一個 Response 物件

fetch(api)
    .then(response => {
        console.log(response); // response 是一個 Response 物件
    });
  • 回應狀態碼(status)和回應是否成功的指示(ok
  • 回應的標頭(headers
  • 回應的內容(這內容是未解析的原始格式)

因此,在 .then() 中接收到的 Response 物件,並不直接包含資料,而是提供了解析內容的方法。

如何從 Response 中取得實際資料?

Response 物件內不包含最終的資料,而是提供了解析的方式。常用的解析方法有:

  • response.json(): 將內容解析為 JSON 格式
  • response.text(): 將內容解析為純文字
  • response.blob(): 將內容轉為二進制格式的 Blob

以下範例展示了如何解析 JSON 資料:

fetch(api)
    .then(response => {
        if (!response.ok) {
            throw new Error("Network response was not ok");
        }
        return response.json(); // 解析 JSON 格式的資料
    })
    .then(data => {
        console.log(data); // 這裡的 data 是 JSON 解析後的實際資料
    })
    .catch(error => {
        console.error("There was a problem with the fetch operation:", error);
    });

在這個範例中:

  1. fetch(api) 返回的 Promise 自動 resolve,並傳回 Response 物件。
  2. 呼叫 response.json() 會將回應內容解析為 JSON,並返回一個新的 Promise
  3. Promise resolve 後的資料會傳入下一個 .then(data => {...})data 參數,這就是 API 回傳的最終資料。

補充:response.json() vs JSON.parse(response)

response.json()JSON.parse(response) 有著顯著的不同,主要是在處理方式和使用場合上。

response.json()

  • 作用response.json()fetch API 專用的方法,用來解析 Response 物件中的 JSON 格式的資料。
  • 返回:它會返回一個 Promise,該 Promise resolve 後會提供解析後的 JavaScript 物件。

    因此,在使用 response.json() 後,你需要用 .then() 來獲取解析後的資料。
  • 適用場景:用於解析從 fetchResponse 物件中提取的資料,適合處理 API 回應中的 JSON。

範例:

fetch(api)
    .then(response => response.json()) // 返回一個解析後的 JSON 資料
    .then(data => {
        console.log(data); // 這裡的 data 是已解析的 JSON 物件
    });

JSON.parse(response)

  • 作用JSON.parse() 是一個 JavaScript 標準方法,用於將 JSON 格式的字串解析成 JavaScript 物件。
  • 返回:它直接返回解析後的 JavaScript 物件,而不是一個 Promise
  • 適用場景:用於已經是純字串格式的 JSON 資料。也就是說,如果你已經有一個 JSON 格式的字串(而不是 Response 物件),就可以使用 JSON.parse() 來將其轉換為 JavaScript 物件。

範例:

const jsonString = '{"name": "John", "age": 30}';
const data = JSON.parse(jsonString);
console.log(data); // 這裡的 data 是已解析的 JSON 物件

差異總結

  • response.json() 適用於 fetch 返回的 Response 物件,而 JSON.parse() 只能用於 JSON 格式的純字串。
  • response.json() 返回的是 Promise,而 JSON.parse() 直接返回解析後的物件。

因此,在 fetch 的回應中使用 response.json() 是更合適的選擇。

更詳細的過程

當我們執行這段 fetch 代碼時,解析資料的每個階段會在不同的時間點完成,以下是每個 .then()Promise resolve 時間點,並配有一張流程圖來清晰解釋整個過程。

流程圖

開始

fetch(api) ➔ 返回 Promise
  ↓         (等待回應)
伺服器回應成功,Promise resolve,進入第一個 .then()

response.json() ➔ 返回 Promise
  ↓         (開始解析 JSON)
JSON 解析完成,Promise resolve,進入下一個 .then()

取得解析後的資料 (data),可以使用

.catch() ➔ 如果有錯誤,進入這裡
  1. 第一個 .then:當 fetchPromise 被 resolve 後,我們進入第一個 .then(response => response.json())

    這時候,response.json() 開始解析 JSON 資料,但它會返回一個新的 Promise,因為解析資料是非同步的。
  2. 第二個 .then:這個新的 Promise 一旦完成 JSON 解析並 resolve,我們才能取得解析後的資料。因此,需要再加一個 .then(data => {...}) 來接收解析完成的資料 data

所以整體來看,第一個 .then(response => response.json()) 會返回一個 Promise,而第二個 .then(data => {...}) 才能接收解析後的最終資料

代碼

fetch(api)
    .then(response => response.json()) // response.json() 返回一個 Promise
    .then(data => {
        console.log(data); // 這裡的 data 是解析後的 JavaScript 物件
    })
    .catch(error => {
        console.error("Error:", error);
    });

每個階段的 resolve 時間點

  1. fetch(api): fetch 發送請求並立即返回一個 Promise
    • 時間點fetch 請求到伺服器回應成功時,這個 Promise 會被 resolve,並返回一個 Response 物件,進入第一個 .then(response => response.json())
  1. response.json(): response.json() 開始解析 JSON,並返回一個新的 Promise
    • 時間點:當 response.json() 的解析完成時,這個 Promise 會被 resolve,並返回解析後的 JavaScript 物件,進入下一個 .then(data => {...})
  1. .then(data => {...}): 在這裡,我們可以取得解析後的資料 data
    • 時間點:此 Promise 會在 response.json() 解析完成並將資料提供給 .then(data => {...}) 後 resolve。
  1. .catch(error => {...}): 如果在 fetch 請求或 response.json() 解析過程中發生錯誤,程式會跳過 .then() 並進入 .catch(error => {...})
    • 時間點:當請求過程中有任何錯誤,會馬上觸發 .catch()

在這段代碼中,每個階段 resolve 的時間點取決於以下條件:

  • fetch 取得伺服器回應後,進入第一個 .then(response => response.json())
  • response.json() 解析完成後,進入下一個 .then(data => {...}),並提供解析後的 JavaScript 物件 data

總結:fetch 到底取得什麼?

簡而言之,fetch 並不直接返回資料,而是通過 Promise 返回一個 Response 物件

我們需要透過 Response 的解析方法(如 json())來提取出最終的資料內容。

這樣的設計讓 fetch 更加靈活,適合處理各種格式的回應資料,比如 JSON、文字和二進制檔案。

希望這篇文章讓你對 fetch 的運作有更清楚的理解!

Similar Posts

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *