在 JavaScript 中,fetch
API 是一種常見的 HTTP 請求工具,但其需要兩次 await
的機制可能讓初學者感到疑惑。本文將通過示例與解析,理解這一特性。
基礎示例
const response = await fetch('https://api.example.com/data');
const data = await response.json();
上面的代碼為什么需要兩次 await
?
Fetch 的兩階段流程
1. 獲取響應
調用 fetch
時,它返回一個 Promise,在網絡請求完成后解析為 Response 對象:
- 僅獲取元數據:此時只獲取響應頭信息,正文尚未處理。
2. 解析響應正文 ??
Response 對象包含的方法(如 .json()
、.text()
)用于讀取正文,這些方法返回另一個 Promise,因為讀取和解析正文是異步操作。
第一次 await
的內部流程
當你執行以下代碼:
const response = await fetch(url);
1. 發送請求
瀏覽器向指定 URL 發起網絡請求:
2. 接收響應元數據
- 服務器返回狀態行(如
HTTP/1.1 200 OK
)和響應頭后,fetch
的 Promise 解析。 - 響應頭:如
Content-Type: application/json
3. 構造 Response 對象
- Headers:通過
response.headers
獲取。
第二次 await
的內部流程
當你執行以下代碼:
const data = await response.json();
1. 讀取正文流
Response 對象的正文被解析為流:
.json()
:解析為 JSON 并返回 JavaScript 對象。
2. 異步解析
- 流數據被解析為可用內容(如
{ message: "Hello, world!" }
)。
3. 返回解析結果
response.json()
返回的 Promise 解析為解析后的數據,可用于程序邏輯。
為什么需要兩次 await
?
兩次 await
是 Fetch 的設計邏輯,分別解決以下問題:
- 等待網絡請求完成,獲取 Response 對象(包含狀態碼、頭信息等元數據)。
如果跳過任意一次 await
會如何?
- 你將得到一個未解析的 Promise,而非 Response 對象。
- 你將得到未解析的 Promise,而非解析后的數據。
完整示例:帶錯誤處理
以下是一個完整的示例,展示如何正確處理錯誤:
try {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Error fetching data:', error);
}
錯誤處理注意點:
- **檢查
response.ok
**:fetch
不會對 HTTP 錯誤(如 404 或 500)拋出異常。 - 捕獲解析錯誤:如果響應正文不符合預期格式(如 JSON 格式錯誤),解析時也會拋出異常。
常見問題與解決方案
1. 忘記錯誤處理
- 問題:
fetch
默認不會對 HTTP 錯誤拋出異常,可能導致你誤以為請求成功。 - 解決:手動檢查
response.ok
或 response.status
。
2. 忘記第二次 await
- 問題:會導致代碼處理未解析的 Promise,而非實際數據。
- 解決:始終
await
解析方法(如 .json()
)。
3. 舊 API 的影響
- 問題:從
XMLHttpRequest
等同步 API 遷移的開發者可能預期同步行為。 - 解決:理解并適應
fetch
的 Promise 異步設計。
總結
使用 Fetch API 時,兩次 await
是其異步設計的結果:
- **第一次
await
**:確保接收到響應元數據。 - **第二次
await
**:解析響應正文,獲取最終數據。
理解 Fetch 的工作機制能幫助你編寫更高效、可靠的異步代碼!
?
閱讀原文:原文鏈接
該文章在 2024/12/30 14:37:42 編輯過