Fetch API
fetch(url) 会让浏览器发送 HTTP 请求,并立即返回 Promise。该 Promise 通常兑现为 Response,而不是已经解析的 JSON。
先取得 Response,再取得数据
await fetch(...) 得到状态码、响应头和正文流。response.json() 读取正文文本、按 JSON 解析,并返回另一个以 JavaScript 数据兑现的 Promise。
两个独立阶段
请把传输响应和解析正文分开理解。响应可以有重要状态码,但正文未必是 JSON。
📊 从请求到数据
| 表达式 | 结果 | 含义 |
|---|---|---|
| fetch(url) | Promise<Response> | 请求已开始 |
| await fetch(url) | Response | 状态、响应头和正文流 |
| response.json() | Promise<any> | 读取并解析正文 |
| await response.json() | JavaScript 数据 | 解析后的对象或值 |
fetch 返回 Promise
这个独立示例只用 Blob URL 展示返回类型。Blob URL 是浏览器内存资源,并非同源 HTTP endpoint。
const blob = new Blob(['{"drink":"lida tea"}'], { type: "application/json" });
const url = URL.createObjectURL(blob);
const ticket = fetch(url);
console.log(ticket instanceof Promise);
ticket.finally(() => URL.revokeObjectURL(url));
输出为 true。实际项目中可把 Blob URL 换成 /data/drink.json 等 HTTP 路径。
先等待 Response,再等待 JSON
下一个示例创建相同的本地资源,并完成两次等待。
async function loadDrink() {
const blob = new Blob(['{"drink":"lida tea"}'], { type: "application/json" });
const url = URL.createObjectURL(blob);
try {
const response = await fetch(url);
if (!response.ok) throw new Error("HTTP " + response.status);
const data = await response.json();
console.log(data.drink);
} finally {
URL.revokeObjectURL(url);
}
}
loadDrink();
输出为 lida tea。真实的 /data/drink.json 可以包含 {"drink":"lida tea"},读取步骤完全相同。
明确检查 HTTP 错误
即使服务器返回 404 或 500,fetch 通常仍会兑现。网络故障可能导致拒绝,但失败状态码本身通常不会。应检查 response.ok 或 response.status。
const response = new Response("Not found", {
status: 404,
statusText: "Not Found"
});
console.log(response.ok);
console.log(response.status);
构造的响应依次输出 false 和 404,这正是真实 fetch 后要检查的属性。除非 API 明确保证,否则不要把错误页面当 JSON 解析。
json 也返回 Promise
json() 会异步读取并解析正文。
const response = new Response('{"drink":"lida tea"}', {
headers: { "Content-Type": "application/json" }
});
const dataPromise = response.json();
console.log(dataPromise instanceof Promise);
dataPromise.then(data => console.log(data.drink));
输出为 true。执行 await response.json() 后,data 是 JavaScript 对象,data.drink 是字符串。
不依赖 endpoint 的页面示例
示例 fetch 一个 Blob URL,因此可独立运行。它展示流程和状态 200,但不会把它说成服务器请求。
<!DOCTYPE html>
<html>
<body>
<p id="cup">blank</p>
<p id="line">…</p>
<script>
async function load() {
const blob = new Blob(['{"drink":"lida tea"}'], { type: "application/json" });
const url = URL.createObjectURL(blob);
try {
const response = await fetch(url);
if (!response.ok) throw new Error("HTTP " + response.status);
const data = await response.json();
document.getElementById("cup").textContent = data.drink;
document.getElementById("line").textContent =
response.status + " / " + data.drink;
} finally {
URL.revokeObjectURL(url);
}
}
load();
</script>
</body>
</html>
页面显示 200 / lida tea。生产环境应使用 HTTP URL,并在解析前继续检查 ok。
动手试试
在本地服务器创建 /data/drink.json 并替换 Blob URL,再请求不存在的路径,对比 ok 与 status。
常见错误
不要把 fetch 返回的 Promise 当成数据。不要忘记调用并等待 json()。也不要只靠 catch 判断每个 404。
小结
fetch 发送请求,并给出以 Response 兑现的 Promise。先检查 ok,再解析预期正文。response.json() 返回 JavaScript 数据的 Promise。
🧠 测试您的知识
测试您的知识
通过这个互动测验挑战自己,看看你对这个主题的理解程度如何
📝 说明
- 仔细阅读每个问题
- 为每个问题选择最佳答案
- 您可以随时重新参加测验
- 您的进度将显示在顶部