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